<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Takahisa Shiratori on Medium]]></title>
        <description><![CDATA[Stories by Takahisa Shiratori on Medium]]></description>
        <link>https://medium.com/@takashiratori?source=rss-ddc6e69b24f9------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*-68TnlNiMQ8AwX5tcKh90A.png</url>
            <title>Stories by Takahisa Shiratori on Medium</title>
            <link>https://medium.com/@takashiratori?source=rss-ddc6e69b24f9------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 01:10:32 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@takashiratori/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Setting Up Amazon Linux 2023 Desktop on a Graviton EC2 Instance]]></title>
            <link>https://medium.com/@takashiratori/setting-up-amazon-linux-2023-desktop-on-a-graviton-ec2-instance-2a9103705c92?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a9103705c92</guid>
            <category><![CDATA[amazon-linux-2023]]></category>
            <category><![CDATA[graviton]]></category>
            <category><![CDATA[vscode]]></category>
            <category><![CDATA[claude-code]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Sat, 11 Apr 2026 10:29:24 GMT</pubDate>
            <atom:updated>2026-04-11T10:29:24.781Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NY76D8A_SCS3JFK7gT_vtA.png" /></figure><h3>Background</h3><p>I have been using Amazon Linux 2023 (AL2023) EC2 instances with a desktop environment as my development setup. The main reasons for using this environment are as follows:</p><ul><li>I can keep tools like Claude Code running even after closing my Mac</li><li>IAM Role-based authentication is convenient when deploying environments developed with AWS CDK</li><li>I can easily start over from scratch or restore from a previous backup (AMI)</li></ul><p>Until now, I had been using Intel-based instance types. However, for developing with Amazon Bedrock AgentCore, an Arm-based CPU environment is better suited for local testing, so I decided to set up a development environment on a Graviton EC2 instance.</p><p>The steps are almost identical to those in <a href="https://medium.com/@takashiratori/installing-kiro-on-amazon-ec2-desktop-amazon-linux-2023-fb7416209dc4">my previous article</a>. The one difference is that Google Chrome does not provide an Arm Linux build, so I use Firefox as the browser instead.</p><h3>Steps</h3><h4>Launching the EC2 Instance</h4><p>Select c8g.large as the instance type. Configure the security group to allow SSH access from your own IP address.</p><h4>Setting Up the Desktop Environment</h4><p>Connect to the EC2 instance via SSH from your local machine.</p><p><strong>Run on local machine</strong></p><pre>ssh -i &lt;keypair&gt; ec2-user@&lt;address&gt;</pre><p>Install the GNOME desktop.</p><p><strong>Run on EC2</strong></p><pre>sudo dnf groupinstall &quot;Desktop&quot; -y</pre><p>Set a VNC password.</p><p><strong>Run on EC2</strong></p><pre>vncpasswd</pre><p>When prompted with “Would you like to enter a view-only password (y/n)?”, answer <strong>n</strong>.</p><p>Edit the VNC server user configuration file.</p><p><strong>Run on EC2</strong></p><pre>sudo vi /etc/tigervnc/vncserver.users</pre><p>Append the following line:</p><pre>:1=ec2-user</pre><p>Edit the VNC server default configuration file.</p><p><strong>Run on EC2</strong></p><pre>sudo vi /etc/tigervnc/vncserver-config-defaults</pre><p>Append the following lines:</p><pre>session=gnome<br>securitytypes=vncauth,tlsvnc<br>geometry=1920x1080<br>localhost<br>alwaysshared</pre><p>Start the VNC server and log out of the EC2 instance.</p><p><strong>Run on EC2</strong></p><pre>sudo systemctl start vncserver@:1<br>exit</pre><h4>Connecting via VNC</h4><p>Set up an SSH tunnel.</p><p><strong>Run on local machine</strong></p><pre>ssh -i &lt;keypair&gt; -L 5901:localhost:5901 -N ec2-user@&lt;address&gt;</pre><p>On your Mac, open Finder and select Go &gt; Connect to Server from the menu bar. Enter <strong>vnc://localhost:5901</strong> as the destination and input the VNC password you configured earlier to connect to the desktop.</p><h4>Additional Configuration</h4><p>Once you have confirmed the desktop connection, enable VNC server auto-start on boot and disable the screen saver.</p><p><strong>Run on EC2</strong></p><pre>sudo systemctl enable vncserver@:1<br>gsettings set org.gnome.desktop.session idle-delay 0</pre><h4>Installing Visual Studio Code</h4><p><strong>Run on EC2</strong></p><pre>sudo rpm — import https://packages.microsoft.com/keys/microsoft.asc &amp;&amp;<br>echo -e &quot;[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\nautorefresh=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc&quot; | sudo tee /etc/yum.repos.d/vscode.repo &gt; /dev/null<br><br>dnf check-update &amp;&amp;<br>sudo dnf install code</pre><h4>Installing Claude Code</h4><p><strong>Run on EC2</strong></p><pre>curl -fsSL https://claude.ai/install.sh | bash</pre><h3>Conclusion</h3><p>I successfully set up an Amazon Linux 2023 desktop environment on a Graviton (Arm) EC2 instance. The procedure was nearly identical to that used for Intel-based instances. The one notable difference specific to the Arm environment is that Google Chrome does not provide an Arm Linux build. Use an alternative browser such as Firefox as needed.</p><h3>References</h3><ul><li><a href="https://docs.aws.amazon.com/linux/al2023/ug/installing-gnome-al2023.html">Installing GNOME on Amazon Linux 2023</a></li><li><a href="https://docs.aws.amazon.com/linux/al2023/ug/vnc-configuration-al2023.html">VNC configuration on Amazon Linux 2023</a></li><li><a href="https://code.visualstudio.com/docs/setup/linux">Visual Studio Code on Linux</a></li><li><a href="https://code.claude.com/docs/en/setup">Claude Code setup</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a9103705c92" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ストックオプション(SO)の税金について Gemini に相談しながら理解したことまとめ ~税制非適格 SO 行使に伴う確定申告にあたって~]]></title>
            <link>https://medium.com/@takashiratori/%E3%82%B9%E3%83%88%E3%83%83%E3%82%AF%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-so-%E3%81%AE%E7%A8%8E%E9%87%91%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6-gemini-%E3%81%AB%E7%9B%B8%E8%AB%87%E3%81%97%E3%81%AA%E3%81%8C%E3%82%89%E7%90%86%E8%A7%A3%E3%81%97%E3%81%9F%E3%81%93%E3%81%A8%E3%81%BE%E3%81%A8%E3%82%81-%E7%A8%8E%E5%88%B6%E9%9D%9E%E9%81%A9%E6%A0%BC-so-%E8%A1%8C%E4%BD%BF%E3%81%AB%E4%BC%B4%E3%81%86%E7%A2%BA%E5%AE%9A%E7%94%B3%E5%91%8A%E3%81%AB%E3%81%82%E3%81%9F%E3%81%A3%E3%81%A6-752cc8be75dd?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/752cc8be75dd</guid>
            <category><![CDATA[税金]]></category>
            <category><![CDATA[スタートアップ]]></category>
            <category><![CDATA[確定申告]]></category>
            <category><![CDATA[外資系企業]]></category>
            <category><![CDATA[ストックオプション]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Sun, 15 Mar 2026 09:58:18 GMT</pubDate>
            <atom:updated>2026-03-15T10:00:26.749Z</atom:updated>
            <content:encoded><![CDATA[<h3>免責事項</h3><p>この記事は、税務の専門家ではない私が、確定申告にあたって不明点を Gemini に問い合わせるなどして理解した内容をまとめたものです。誤りを含む可能性があります。正確な申告のためには、税理士にご相談ください。また、本記事の内容を参考にした結果生じた損害について、筆者は一切の責任を負いません。</p><h3>背景</h3><p>私は昨年（2025年）5月に外資系スタートアップを退職しました。退職時にストックオプション(SO)を行使しました。この SO の行使により、2026年2〜3月に確定申告が必要になったため, Gemini に問い合わせるなどして理解を深めました。本記事ではその内容をまとめます。</p><h3>ストックオプションについて</h3><p>ストックオプション( Stock Option, SO )とは、あらかじめ定められた特定の価格（行使価格）で、将来的に自社の株式を購入できる権利のことです。スタートアップ企業では、従業員に対する報酬の一形態として無償で付与されることが多く、会社が成長して株価が行使価格を上回った際に、その差額を利益として得ることを目指します。権利の取得時点では株式の購入は行われず、権利行使(Exercise)を実施して初めて株式を取得できます。あくまでも「権利」なので、行使しないという選択肢もあります。</p><h4>関連用語</h4><ul><li><strong>権利行使(Exercise)</strong>: SO を行使し、株を購入すること</li><li><strong>行使価格(Exercise Price)</strong>: SO で株を購入できる価格</li><li><strong>公正市場価値(Fair Market Value, FMV)</strong>: 市場における株の公正な価格</li><li><strong>税制適格 SO</strong> / <strong>税制非適格 SO</strong>: 日本の税制上の区分</li></ul><p>本記事では税制<strong>非</strong>適格 SO を前提とします。税制適格 SO となる要件については、<a href="https://www.meti.go.jp/policy/newbusiness/stock-option.html">経済産業省のサイト</a>を参照してください。外資系スタートアップの SO は、日本の税制が考慮されておらず、税制非適格 SO となることが多いようです。実際に私の場合も、上記サイト中の要件のうちいくつかが満たされていませんでした。また本記事では, SO は無償で提供されることを前提とします。</p><p>通常、以下の2ステップで利益を得ることを目指します：</p><ol><li>ストックオプションを行使して株を買う</li><li>株を売却する</li></ol><h3>ストックオプションに関する税金</h3><p>ここまでの説明で、行使価格よりも売却時の価格が高ければプラスになると考えるかもしれませんが、実際には税金の存在により状況は単純ではありません。日本の税制では、税制非適格 SO の場合、以下のように課税されます</p><ul><li><strong>権利行使時</strong>: （行使時 FMV − 行使価格）× 株数 が<strong>給与所得</strong>として課税される</li><li><strong>売却時</strong>: （売却時株価 − 行使時 FMV）× 株数 が<strong>譲渡所得</strong>として課税される</li></ul><p>以下の図で3つのシナリオを示します。</p><p>— -</p><p><strong>(1) 株価が順調に上昇するケース</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*kIBJQzhwAPPVGBgajZfzZg.png" /><figcaption>図1 株価が順調に上昇するケース</figcaption></figure><p>図1のグラフは、権利行使から売却まで株価が順調に上昇したケースを示しています。権利行使時には「行使時 FMV − 行使価格」の差額が給与所得として課税され、売却時には「売却価格 − 行使時 FMV」の差額が譲渡所得として課税されます。この場合、順調にリターンを得られていると言えます。ただし権利行使から売却までの期間は、給与所得に対する課税分の税金を、利益が確定する前に先行して支払う必要があります。</p><p>— -</p><p><strong>(2) 行使後に株価が下落するケース</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*rxCJQLHKLdY-H0mtbKF4jA.png" /><figcaption>図2 行使後に株価が下落するケース</figcaption></figure><p>図2のグラフは、権利行使後に株価が下落したものの、売却時の株価が行使価格を上回っているケースを示しています。権利行使時には図1と同様に給与所得として課税されます。売却時には行使時 FMV より低い価格で売却するため譲渡損失が発生します。同じ年の他の株の譲渡益との相殺はできるものの、既に支払った「給与所得」の税金は戻ってきません。権利行使から売却までの値下がり幅が大きい場合、税金を含めたトータルリターンがマイナスになる可能性があります。</p><p>— -</p><p><strong>(3) 行使後に株価が行使価格を下回るケース</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*kiZhe4t-R8V3sMif05ePCw.png" /><figcaption>図3 行使後に株価が行使価格を下回るケース</figcaption></figure><p>図3のグラフは、権利行使後に株価が行使価格を下回るまで下落したケースを示しています。売却価格が行使価格を下回るため、投資として完全なマイナスとなります。さらに権利行使時点では含み益があったものとして給与所得に課税されているため、実際の損失に加えて給与所得分の税金も支払う必要があります。株式を売却しても権利行使時のコストを回収できない上に、給与所得に対する課税分の税金を支払わなければならない、最も厳しいケースです。</p><h3>ストックオプションの行使</h3><p>私の場合の SO 行使の流れを以下に示します。</p><p><strong>(1) Carta 上での exercise</strong></p><p>会社が <a href="https://carta.com/">Carta</a>を利用していたため、Carta のプラットフォーム上から権利行使の操作を行いました。</p><p><strong>(2) 振込先銀行口座の把握</strong></p><p>権利行使に伴う代金の振込先として、指定の銀行口座が案内されました。</p><p><strong>(3) ドルでの海外送金</strong></p><p>海外への外貨送金のため、<a href="https://sonybank.jp/services/fcremittance/10.html">ソニー銀行の外貨送金サービス</a>を利用しました。</p><h3>行使後の確定申告</h3><h4>申告金額の計算方法</h4><p>申告するのは「行使によって得た利益」です。計算式は以下の通りです：</p><p>（行使時 FMV − 行使価格）× 株数 × 行使日の TTM レート = 申告する給与所得（円）</p><ul><li><strong>行使時FMV</strong>: 行使日時点の FMV です。私の場合は Carta 上で確認できました</li><li><strong>為替レート</strong>: 外貨建ての場合、行使日の TTM で日本円に換算します。<a href="https://www.murc-kawasesouba.jp/fx/past_3month.php">三菱UFJリサーチ&amp;コンサルティングのサイト</a>で、1990年以降の指定日の TTM を検索できます</li></ul><h4>確定申告書への入力方法（国税庁の確定申告書等作成コーナーを利用する場合）</h4><p>国税庁の確定申告書等作成コーナーにおいて、外貨建てストックオプションの収入の入力手順が以下のように示されています。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/495/1*g5lYmGH8j9nUJ3b6jT-8DQ.png" /><figcaption>図4 給与所得の入力例</figcaption></figure><p>外貨建てストックオプションの収入は、年末調整未済の源泉徴収票という形で入力します。Aの支払金額（円）の欄に「（行使時FMV − 行使価格）× 株数 × 行使日のTTMレート」の計算結果を入力します。</p><p><strong>支払者情報の入力</strong></p><p>ここで入力する支払者は「ストックオプションを発行した会社」の情報を記入します。勤務先の日本法人ではない可能性があります。私の場合, Carta で確認したところ米国の本社から発行されていたため、本社の会社名と住所を入力しました（米国の住所をアルファベットで入力しました）</p><h3>まとめ</h3><ul><li>税制非適格SOの行使により、<strong>（行使時FMV − 行使価格）× 株数</strong> が <strong>給与所得</strong> として課税されます。株を売却していない段階でも申告・納税が必要です</li><li>売却時には <strong>（売却時株価 − 行使時FMV）× 株数</strong> が <strong>譲渡所得</strong> として課税されます</li><li>行使後に株価が下落した場合、税金を含めたトータルリターンがマイナスになるリスクがあります。既に支払った給与所得の税金は、その後の株価下落があっても原則として還付されません</li><li>私の場合、SO の行使は Carta 上で実施し、行使代金の振込にはソニー銀行の外貨送金サービスを利用しました</li><li>確定申告では, <strong>（行使時FMV − 行使価格）× 株数 × 行使日のTTMレート</strong> を給与所得として、「年末調整未済」の形式で入力します。支払者は SO を発行した会社（勤務先の日本法人ではない可能性あり）を記入します</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=752cc8be75dd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Installing Dify Community Edition on Amazon EC2 (Amazon Linux 2023)]]></title>
            <link>https://medium.com/@takashiratori/installing-dify-community-edition-on-amazon-ec2-amazon-linux-2023-276a6dcbc34c?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/276a6dcbc34c</guid>
            <category><![CDATA[ec2]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[amazon-linux-2023]]></category>
            <category><![CDATA[genrative-ai]]></category>
            <category><![CDATA[dify]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Fri, 06 Feb 2026 13:16:15 GMT</pubDate>
            <atom:updated>2026-02-06T13:38:49.452Z</atom:updated>
            <content:encoded><![CDATA[<p>This article explains the steps to install Dify (Self-Hosted, Community Edition) on Amazon EC2 (Amazon Linux 2023). Starting from the launch of the EC2 instance, we will connect to the Dify sign-up page via SSH port forwarding at the end of this article.</p><h3>Background</h3><p>Dify is an LLM application development platform that allows you to build and operate LLM applications using a GUI. You can get started for free by using Dify’s cloud service sandbox. However, the free version has the following limitations and inconveniences:</p><ul><li>The number of the user is limited to one person, and it cannot be used by a team.</li><li>Only up to five apps can be created.</li><li>API Key of LLM provider, e.g. OpenAI, has to be prepared.</li></ul><p>If you have an AWS account, installing Dify Self-Hosted Service Community Edition on Amazon EC2 provides the following benefits:</p><ul><li>Can be used by multiple people</li><li>More than 5 apps can be create</li><li>By accessing Amazon Bedrock with IAM Role, LLMs like GPT and Claude can be used without preparing API Keys.</li></ul><p>This article describes how to install the self-hosted version of Dify on Amazon EC2 by following the official instructions below.<br><a href="https://docs.dify.ai/ja/self-host/quick-start/docker-compose">https://docs.dify.ai/ja/self-host/quick-start/docker-compose</a></p><h3>Launching EC2</h3><p>First, launch an EC2 instance with the following specifications:</p><ul><li><strong>AMI</strong>: ami-0532be01f26a3de55 (the latest Amazon Linux 2023 at the time I ran this procedure)</li><li><strong>Instance type</strong>: c8i.xlarge</li><li><strong>EBS</strong>: 32 GiB</li><li><strong>Security Group</strong>: Allow SSH (TCP 22) from My IP</li></ul><h3>Connecting to EC2 and setting up the environment</h3><p>Connect to your EC2 instance via SSH.</p><ul><li>In local:</li></ul><pre>ssh -i &lt;keypair&gt; ec2-user@&lt;address&gt;</pre><p>After connecting, install Git and Docker, and start Docker.</p><ul><li>On EC2:</li></ul><pre>sudo dnf update -y<br>sudo dnf install -y git docker<br>sudo systemctl start docker<br>sudo systemctl enable docker</pre><p>Next, install Docker Compose as a plugin and configure it to run Docker commands as the current user.</p><ul><li>On EC2:</li></ul><pre>mkdir -p ~/.docker/cli-plugins/<br>curl -SL &quot;https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)&quot; -o ~/.docker/cli-plugins/docker-compose<br>chmod +x ~/.docker/cli-plugins/docker-compose<br>sudo usermod -aG docker $USER<br>newgrp docker</pre><h3>Installing and launching Dify</h3><p>We will get the latest Dify repository from GitHub, prepare the environment configuration files, and then use Docker Compose to launch a group of containers in the background.</p><ul><li>On EC2:</li></ul><pre>git clone --branch &quot;$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)&quot; https://github.com/langgenius/dify.git<br>cd dify/docker<br>cp .env.example .env<br>docker compose up -d</pre><h3>Configuring automatic startup</h3><p>Register Dify as a systemd service so that it will start automatically when the EC2 instance is rebooted.</p><ul><li>On EC2:</li></ul><pre># Create a configuration file to manage Dify as a service using systemd.<br># In this file, define the Dify container to run after the Docker service has started.<br>sudo tee /etc/systemd/system/dify.service &lt;&lt; &#39;EOF&#39;<br>[Unit]<br>Description=Dify Docker Compose Application<br>Requires=docker.service<br>After=docker.service<br>[Service]<br>Type=oneshot<br>RemainAfterExit=yes<br>WorkingDirectory=/home/ec2-user/dify/docker<br>ExecStart=/usr/bin/docker compose up -d<br>ExecStop=/usr/bin/docker compose down<br>TimeoutStartSec=0<br>User=ec2-user<br>Group=ec2-user<br>[Install]<br>WantedBy=multi-user.target<br>EOF<br><br># Reflect the created service settings to the system and enable Dify so that it starts automatically when the OS starts.<br>sudo systemctl daemon-reload<br>sudo systemctl enable dify.service</pre><h3>Access from a browser</h3><p>Disconnect the SSH connection, set up port forwarding, and reconnect. This will allow you to securely access Dify (port 80) on the EC2 instance via port 8080 on your local machine.</p><ul><li>In local:</li></ul><pre>ssh -i &lt;keypair&gt; -L 8080:localhost:80 ec2-user@&lt;address&gt;</pre><p>After connecting, access the following URL in your local browser. If the initial setup screen appears, the installation was successful.<br><a href="http://localhost:8080/install">http://localhost:8080/install</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OaMN_PcxOqOmNR-7__2Qgw.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=276a6dcbc34c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Amazon Linux 2023 (AL2023) のデスクトップを日本語化する]]></title>
            <link>https://medium.com/@takashiratori/amazon-linux-2023-al2023-%E3%81%AE%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%82%92%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%8C%96%E3%81%99%E3%82%8B-05afbcd2cd6c?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/05afbcd2cd6c</guid>
            <category><![CDATA[クラウド]]></category>
            <category><![CDATA[amazon-linux-2023]]></category>
            <category><![CDATA[amazon-ec2]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[クラウドコンピューティング]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Tue, 20 Jan 2026 07:47:20 GMT</pubDate>
            <atom:updated>2026-01-20T07:49:02.793Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://medium.com/@takahisa.shiratori/installing-kiro-on-amazon-ec2-desktop-amazon-linux-2023-fb7416209dc4">Installing Kiro on Amazon EC2 Desktop</a> では, Amazon Linux 2023 の Amazon EC2 を用いてデスクトップサーバーを構築しました。今回は、このデスクトップサーバーを日本語化する手順を示します</p><h3>(1) コマンドでの設定</h3><p>以下のコマンドを、デスクトップサーバーとして構築した EC2 において実行します</p><pre>sudo timedatectl set-timezone Asia/Tokyo<br>sudo localectl set-locale LANG=ja_JP.UTF-8<br>localectl list-keymaps | grep jp<br>sudo localectl set-keymap jp-OADG109A<br>sudo yum install -y google-noto-sans-japanese-fonts<br>sudo dnf install -y ibus-anthy</pre><p>その後, EC2 を Stop/Start します</p><h3>(2) デスクトップ上での設定</h3><p>デスクトップに接続（接続方法は<a href="https://medium.com/@takahisa.shiratori/installing-kiro-on-amazon-ec2-desktop-amazon-linux-2023-fb7416209dc4">前の記事</a>参照）すると、以下のような選択肢が表示されます。ここでは「古い名前のままにする」を選択して先に進みます</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*89rq8Yv8LPiS5iCTPoiaCg.png" /></figure><p>画面左上のアイコン &gt; 白い9つの点のアイコン(Show Apps) &gt; 設定 &gt; キーボード の順に進み, Add Input Source をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/849/1*EXRgDXmhcBBBXmLe01g5ow.png" /></figure><p>以下の一覧から「日本語」を選択します</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C4kFkXgTn3WxdSLuRtjIOA.png" /></figure><p>以下の一覧から「日本語(Anthy)」を選択します</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bh_XLVbJMwrpiYan7UqmeA.png" /></figure><p>キーボード設定の画面に自動的に戻ります。ここから、手元の Mac の ABC キーで日本語と英語を切り替えられるようにします。まず、キーボード設定の画面の最下部、キーボードショートカット欄の View and Customize Shortcuts をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6hklo9spp4J5Ql5w6zneVQ.png" /></figure><p>以下の一覧から「タイピング」を選択します</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*x1SRhpP_r2N_Asquh8TyIg.png" /></figure><p>「次の入力ソースへ切り替える」をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2CJjK9x46L0v_7IGP6JJ8g.png" /></figure><p>日本語と英語の切り替え時に使用したいキーを押します。ここでは ABC キーを押します. Romaji キーとして認識されました</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bFEwCHmCfo4CgfWZyuqwjQ.png" /></figure><p>以上を完了すると</p><ul><li>デスクトップ上の各種表示が日本語である</li><li>日本語が入力可能である</li><li>OS のタイムゾーンが日本時間である</li></ul><p>という環境の Linux デスクトップを使用することができます</p><p>参考: <a href="https://qiita.com/constdrop/items/62c618c0a9a2719c54a1">Amazon Linux 2023のデスクトップにリモートアクセス — Qiita</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=05afbcd2cd6c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ペーパードライバー講習などの記録]]></title>
            <link>https://medium.com/@takashiratori/%E3%83%9A%E3%83%BC%E3%83%91%E3%83%BC%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E8%AC%9B%E7%BF%92%E3%81%AA%E3%81%A9%E3%81%AE%E8%A8%98%E9%8C%B2-890f55294e38?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/890f55294e38</guid>
            <category><![CDATA[日本語]]></category>
            <category><![CDATA[運転免許]]></category>
            <category><![CDATA[東京]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Mon, 21 Jul 2025 09:46:04 GMT</pubDate>
            <atom:updated>2025-07-21T09:46:04.893Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/377/1*U_eoDvY3Tis7eUf40Pqi1g.png" /></figure><h3>はじめに</h3><p>私は普通自動車運転免許を取得してから約20年間、ほぼ車を運転したことがなく、いわゆるペーパードライバーの状態であった。しかし、数ヶ月前に転職をし、お客様訪問に際して車を運転できた方が望ましい状況となった。そこで、安定した車の運転をできるようにするため、以下を実施した（または実施している）</p><h3>(1) 仕事での運転（1回目）</h3><p>長野市郊外の比較的交通量が少ない道路で、4~5kmほど運転する機会があった。事故なく運転できたものの、講習を受けて運転を再習得する必要性を感じた</p><h3>(2) ペーパードライバー講習（1回目）</h3><p><a href="https://general-h.com/paper/">ペーパードライバー講習東京 上野校</a> で、2時間のペーパードライバー講習を受けた。助手席のブレーキ付きの通常の乗用車（外観では講習中の車ということは特にはわからない）で、インストラクターの方が集合場所である上野駅に迎えに来てくれた。エンジンのかけ方、ギアチェンジやサイドブレーキの操作方法、サイドミラーやバックミラーの調整の目安などの基本的な説明を受けた。運転を始める前に「初心者マークをつけますか」と聞かれたのでつけてもらうことにした。前半の約1時間で一般道を運転した。上野公園付近の区画や上野駅公園口のロータリーなどを周回したのち、浅草周辺を運転した。後半の約1時間で、駐車場にバックで駐車する練習をした</p><h3>(3) ペーパードライバー講習（2回目）</h3><p>高速道路での運転に不安があったため、同2時間のペーパードライバー講習で首都高での講習を受けた。ルートは正確には覚えていないが、上野近辺で首都高に入り、お台場、新木場、駒形パーキングエリアなどを通り宝町で首都高を出たような気がする。駒形パーキングエリアではバックで駐車する練習をした。1回目と同様、初心者マークをつけて講習を受けた</p><h3>(4) 仕事での運転（2回目）</h3><p>大阪府南部から新大阪駅まで、約50kmの運転をした。ルートには阪和自動車道と阪神高速が含まれる</p><h3>(5) カーシェアによる日常的な運転</h3><p>ペーパードライバーに戻ることを防ぐことを目的として、<a href="https://share.timescar.jp/">タイムズカー</a>を個人で契約して日常的に車を運転することとした。現在のところ、週1~2回、片道2~4km程度のルートを往復している</p><h3>その他</h3><p>バックでの駐車については、以下の記事および動画を参考にしている</p><p><a href="https://gazoo.com/ilovecars/driving/17/08/18/">車庫入れのコツ（クルマの運転 苦手克服） | クルマ情報サイトｰGAZOO.com</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fyz-werIxyC8%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dyz-werIxyC8&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fyz-werIxyC8%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/712b2d5ae61eb9defd7635adaab0d466/href">https://medium.com/media/712b2d5ae61eb9defd7635adaab0d466/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=890f55294e38" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Installing Kiro on Amazon EC2 Desktop (Amazon Linux 2023)]]></title>
            <link>https://medium.com/@takashiratori/installing-kiro-on-amazon-ec2-desktop-amazon-linux-2023-fb7416209dc4?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/fb7416209dc4</guid>
            <category><![CDATA[amazon-linux-2023]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[kiro]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Fri, 18 Jul 2025 06:26:58 GMT</pubDate>
            <atom:updated>2026-03-11T09:19:26.048Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction</h3><p>On July 14, 2025, <a href="https://kiro.dev/blog/introducing-kiro/">AWS launched its new AI IDE, Kiro</a>. To leverage Kiro, I opted to install it on an Amazon EC2 Desktop instance for a few key reasons:</p><ul><li><strong>Flexibility for experimentation</strong>: The ability to create Amazon Machine Images (AMIs), terminate instances, and launch new ones from AMIs is invaluable for iterative testing and troubleshooting.</li><li><strong>Persistent operation</strong>: Kiro can continue running on the EC2 instance even after I close my MacBook, ensuring uninterrupted work.</li></ul><p>This article details the process of configuring Amazon Linux 2023 as a desktop server, establishing a VNC connection from a Mac, and subsequently installing Kiro on the desktop server.</p><p><strong>NOTE</strong>: I’ve since discovered that the Kiro download page has transitioned to a “Join Waitlist” form. It appears immediate access to the installer is no longer available.</p><h3>Launching EC2</h3><p>To begin, launch an EC2 instance with the following specifications:</p><ul><li>AMI ID: ami-0150ccaf51ab55a51</li><li>Instance Type: t3.medium</li><li>Security Group: Allow TCP 22 inbound from My IP</li></ul><h3>Installing Linux GUI and VNC</h3><p>First, connect to your EC2 instance via SSH:</p><ul><li>In local:</li></ul><pre>ssh -i &lt;keypair&gt; ec2-user@&lt;address&gt;</pre><p>Once connected, install the Linux GUI and TigerVNC server using these commands:</p><ul><li>On EC2:</li></ul><pre>sudo dnf groupinstall &quot;Desktop&quot; -y<br>sudo dnf install -y tigervnc-server</pre><p>Next, set up your VNC password:</p><ul><li>On EC2:</li></ul><pre>vncpasswd</pre><p>When prompted “Would you like to enter a view-only password (y/n)?”, I responded with n, as a view-only password was not necessary for my use case.</p><p>Open the vncserver.users file to configure the VNC user:</p><ul><li>On EC2:</li></ul><pre>sudo vi /etc/tigervnc/vncserver.users</pre><p>Add the following configuration</p><pre>:1=ec2-user</pre><p>Now, open the vncserver-config-defaults file to define VNC server settings:</p><ul><li>On EC2:</li></ul><pre>sudo vi /etc/tigervnc/vncserver-config-defaults</pre><p>Add these configurations:</p><pre>session=gnome<br>securitytypes=vncauth,tlsvnc<br>geometry=1920x1080<br>localhost<br>alwaysshared</pre><p>Start the VNC server and then disconnect your SSH session:</p><ul><li>On EC2:</li></ul><pre>sudo systemctl start vncserver@:1<br>exit</pre><p>To connect from your Mac, configure SSH port forwarding on your local machine:</p><ul><li>In Local:</li></ul><pre>ssh -i &lt;keypair&gt; -L 5901:localhost:5901 -N ec2-user@&lt;address&gt;</pre><p>From your MacBook, open your VNC client by navigating to Finder &gt; Go &gt; Connect to Server. Enter vnc://localhost:5901 as the destination and input the VNC password you configured earlier.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/786/1*LFRRDi22HN939NaxriDFaQ.png" /></figure><p>The Linux Desktop should now appear.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mCxvOWT6Src31n-k-bf5fQ.png" /></figure><h3>Installation of Google Chrome and Kiro</h3><p>Once on the Linux desktop, open a Terminal and execute the following commands:</p><ul><li>On EC2:</li></ul><pre>sudo systemctl enable vncserver@:1<br>gsettings set org.gnome.desktop.session idle-delay 0</pre><p>Now, install and launch Google Chrome:</p><ul><li>On EC2:</li></ul><pre>wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm<br>sudo dnf install ./google-chrome-stable_current_x86_64.rpm<br>google-chrome</pre><p>Follow the on-screen prompts within the Google Chrome GUI to set it as your default web browser.</p><p>Finally, obtain and install Kiro:</p><ul><li>Download the Kiro installer for Linux from <a href="https://kiro.dev/downloads/">https://kiro.dev/downloads/</a> (as noted, you currently need to join the waitlist).</li><li>Double-click the downloaded .tar.gz file to decompress it.</li><li>Double-click the Kiro executable file within the decompressed folder to launch the application.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qMHU2ZNq1X090mTfgiilhg.png" /></figure><h3>References</h3><ul><li><a href="https://docs.aws.amazon.com/linux/al2023/ug/installing-gnome-al2023.html">https://docs.aws.amazon.com/linux/al2023/ug/installing-gnome-al2023.html</a></li><li><a href="https://docs.aws.amazon.com/linux/al2023/ug/vnc-configuration-al2023.html">https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/vnc-configuration-al2023.html</a></li><li><a href="https://dev.classmethod.jp/articles/headless-chrome-on-al2023/">https://dev.classmethod.jp/articles/headless-chrome-on-al2023/</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fb7416209dc4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Amazon QuickSight によるマネーフォワード ME のデータの可視化]]></title>
            <link>https://medium.com/@takashiratori/amazon-quicksight-%E3%81%AB%E3%82%88%E3%82%8B%E3%83%9E%E3%83%8D%E3%83%BC%E3%83%95%E3%82%A9%E3%83%AF%E3%83%BC%E3%83%89-me-%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%8F%AF%E8%A6%96%E5%8C%96-95858cd6b0a4?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/95858cd6b0a4</guid>
            <category><![CDATA[家計簿]]></category>
            <category><![CDATA[マネーフォワード]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[日本語]]></category>
            <category><![CDATA[quicksight]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Sun, 02 Feb 2025 08:33:24 GMT</pubDate>
            <atom:updated>2025-02-02T08:33:24.915Z</atom:updated>
            <content:encoded><![CDATA[<h3>この記事について</h3><p>この記事では、マネーフォワード ME のデータを Amazon QuickSight で可視化した取組を紹介します。データの処理・保存のために Amazon S3 と AWS Lambda も使用しました. Amazon QuickSight による可視化により、より良い決済方法をデータに基づき選定したり、家計を多角的にモニタリング・分析したりすることができるようになりました</p><h3>背景</h3><p>私は家計の管理に<a href="https://moneyforward.com/me">マネーフォワード ME</a> を使用しています。金融機関や各種決済方法（クレジットカード、コード決済など）のデータを自動的に集約できる便利なサービスです。ただし、特定の目的のために家計情報を把握・分析しようとすると、標準で備わっている機能では足りないことがありました</p><p>例えば「自分のライフスタイルにおいて、どの決済方法を使えばポイント還元率が高くなるか」を検討したいとします。数年前までは、コード決済各社などがポイント還元率の高さを競っていたため、幅広い買い物で高いポイント還元率（3%程度）を得ることは難しくありませんでした。しかし現在は「一定金額以上の決済をした場合に限り還元率が高くなる」「特定の店舗での決済のみ還元率が高くなる」など、高還元率の提供に際して条件がつくことが多くなっています。したがって、自分のライフスタイルに合った決済方法を選ぶには、年間や月間の決済金額を把握したり、支払い金額の大きい支出先がどこなのかを把握することが重要となります。マネーフォワード ME が機能として提供するグラフでは、支出額グラフの内訳として表示できるのが項目別（食費、交通費など）に限られており、支出先別（セブンイレブン、JR東日本など）で表示することができません。また年間や月間の支出金額について、単一の決済方法に対しては簡単に把握できるものの、複数の決済方法を合算して表示させる機能は提供されていません</p><h3>目的</h3><p>本取組は、最適な決済方法の選定に向けて有益な知見を得ることを目的として、データを可視化する環境を構築しました. Amazon QuickSight を情報の可視化のために使用しました。可視化に際してデータの前処理をしたかったため, AWS Lambda を使用しました. Amazon QuickSight のデータソースとしては、マネーフォワード ME の出力データ（CSVファイル）を読み込ませたいことから, Amazon S3 を選択しました</p><h3>構成図とデータ更新手順</h3><p>マネーフォワード ME のデータを Amazon QuickSight で可視化するためのシステム構成図と、月に1回行うデータ更新の手順を以下に示します</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*SL03sGCvws6lMeO-s2imdA.png" /><figcaption>図1 システム構成図とデータ更新手順</figcaption></figure><p>(1) マネーフォワード ME から CSV をダウンロードします</p><p>(2) CSV のファイル名を命名規則に合わせて変更します</p><p>(3) CSV を Amazon S3 にアップロードします</p><p>(4) 自動的に Lambda Function が起動され、編集後の CSV ファイルが保存されます<br>この Lambda Function では、可視化に先立ってデータの前処理をしています。例えば、同一の支出先が決済方法によって異なる名称で保存されていることがあるので、この表記統一などをしています</p><p>(5) QuickSight の Dataset を手動で更新します</p><h3>グラフ例</h3><p>家計情報を公開するのは気が引けるため、ここでは、今回決済方法の変更を検討した対象について、支出先別金額割合を示します。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YuuskvGVBAh5MfZ75PYlIQ.png" /><figcaption>図2 Amazon QuickSight で可視化した支出先別金額割合</figcaption></figure><p>無難そうなところだけ表示すると、ヨドバシカメラ（店舗・通販の合計）、セブンイレブン, Amazon などでの支出金額が大きいことがわかりました。このような表示方法は、マネーフォワード ME の機能としては提供されておらず、外部ツール（本取組においては Amazon QuickSight）の活用により可能となりました</p><h3>まとめなど</h3><p>Amazon QuickSight でマネーフォワード ME のデータを可視化することで、決済方法選定に際しての有益な情報を得ることができました。加えて、豊富なグラフ形式やフィルタリング条件で可視化することにより、多角的に家計をモニタリングできるようになりました</p><p>現構成の問題点としては、データ更新時に手動でマネーフォワード ME から CSV ファイルをダウンロードしなければならないという点が挙げられます。マネーフォワード ME は個人向けに API を公開していないため、現時点ではこの作業は手動にせざるを得ないと判断しました。理想的には、データ更新を API などを活用して自動化し、手間を削減してデータの更新頻度を上げたいところです</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=95858cd6b0a4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OpenFOAMとGPyOptとRescaleで、CFDの最適化ワークフローを実現する]]></title>
            <link>https://medium.com/@takashiratori/openfoam%E3%81%A8gpyopt%E3%81%A8rescale%E3%81%A7-cfd%E3%81%AE%E6%9C%80%E9%81%A9%E5%8C%96%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B-992e260af690?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/992e260af690</guid>
            <category><![CDATA[optimization]]></category>
            <category><![CDATA[rescale]]></category>
            <category><![CDATA[日本語]]></category>
            <category><![CDATA[openfoam]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Mon, 27 Apr 2020 01:38:22 GMT</pubDate>
            <atom:updated>2020-04-27T01:38:22.646Z</atom:updated>
            <content:encoded><![CDATA[<p>最適化アルゴリズムと数値流体解析を組み合わせたワークフローを、クラウド上の計算資源を使って動かす<a href="https://github.com/TakahisaShiratori/bayesianopt-openfoam-rescale/blob/master/damBreak_with_rescale_persistent_cluster.ipynb">実例</a>を示す。<a href="http://www.opencae.or.jp/activity/symposium/opencae_symposium2019/training/">オープンCAEシンポジウム2019トレーニング</a>で<a href="https://github.com/TatsuyaKatayama/OpenFOAMandBaysianOpt_Notebooks">教材として使用された Jupyter Notebook</a> をベースに、最適化ライブラリとして<a href="http://sheffieldml.github.io/GPyOpt/">GPyOpt</a>, 流体解析ソフトウェアとして<a href="https://openfoam.org/">OpenFOAM</a>を使用する。<a href="https://www.rescale.com/">Rescale</a>をOpenFOAMの実行環境として使用し、マルチコア・マルチノードでの解析や、商用の流体解析ソフトウェア導入への拡張性を持たせる。クラウドHPCクラスタの起動に要する時間を削減するため、RescaleのPersistent Clusterを使用する</p><h3>背景</h3><p>最適化アルゴリズムと、流体解析・構造解析を組み合わせて設計の最適化を自動化する試みがある。複数条件での解析を実行し、その結果を踏まえて最適化アルゴリズムで次の解析条件を決め、再度複数条件の解析を実行するというものである。この種の自動最適化は、いくつかの要因により、より低コストで試すことができるようになってきている。例えば、最適化アルゴリズムのライブラリの発達、クラウドコンピューティングの普及によるハードウェア初期コストの低下、商用解析ソフトウェアの従量課金体型やオープンソースソフトウェアの充実などがその要因として挙げられる</p><p>この記事では、最適化アルゴリズムと数値流体解析(Computational Fluid Dynamics, CFD)を組み合わせたワークフローを、クラウド上の計算資源を使って動かす実例を示す。コードと実行結果は, Jupyter Notebook <a href="https://github.com/TakahisaShiratori/bayesianopt-openfoam-rescale/blob/master/damBreak_with_rescale_persistent_cluster.ipynb">damBreak_with_rescale_persistent_cluster.ipynb</a> として公開している。この Notebook は、<a href="http://www.opencae.or.jp/activity/symposium/opencae_symposium2019/training/">オープンCAEシンポジウム2019トレーニング</a>で教材として使用された Jupyter Notebook, <a href="https://github.com/TatsuyaKatayama/OpenFOAMandBaysianOpt_Notebooks">OpenFOAMandBaysianOpt_Notebooks</a> をベースとしている。CFDソフトと最適化ライブラリは、元の教材を踏襲してOpenFOAMとGPtOptをそれぞれ使用している</p><p>OpenFOAMの実行環境としてRescaleを使用し、最適化アルゴリズムを実行するJupyter Notebookとは環境を分けている。これは以下2点の拡張性を持たせることを目的としている</p><p>1点目は、CFDのマルチノードでの実行である。規模の大きなモデルのCFDを実行する際に、現実的な範囲内の時間で計算を終わらせるためにマルチノードのクラスタが必要になることがある。そのようなモデルと最適化アルゴリズムを組み合わせたい場合、Jupyter NotebookとOpenFOAMが同居していると、クラスタ環境にJupyter Notebookをインストールすることになる。CFD環境を分離しておけば、Jupyter Notebookは例えば手元のPCやGoogle Colabなどの軽めの環境で動かし、CFDはRescaleのマルチノードクラスタで実行するといった構成が可能になる</p><p>2点目は、OpenFOAM以外のCFDやCAEソフトウェアの使用である。例えば商用のCFDソフトウェアと最適化アルゴリズムを組み合わせたい場合、同居環境を構築するには、Jupyter Notebookと商用CFDが両方正常に動作するようにインストールする必要がある。CFD環境がRescaleへ分離されていれば、インストール済みの商用CFDをそのまま使用できる。またワークフローに応じてソフトウェアやバージョンを使い分けることが容易になる</p><p>ただし分離された構成では、両環境間の通信やRescaleでのクラスタ起動に時間を要する。したがってCFDのモデルが小規模な場合は、同居環境の方が最適化ワークフローを短時間で完了できると考えられる。実際、今回題材としているdamBreakの最適化は、元の教材の同居環境の方が短時間で完了できる</p><h3>全体の流れ</h3><p>全体の大まかな流れと構成図を以下に示す</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*4ND6_pjOQ1PbMsq9HteGqQ.png" /></figure><p>ユーザは、<a href="https://github.com/TakahisaShiratori/bayesianopt-openfoam-rescale/blob/master/damBreak_with_rescale_persistent_cluster.ipynb">GitHub上で公開されたノートブックファイル</a>を、 Jupyter Notebook環境で編集・実行することができる</p><p>ノートブックファイル内のコードは、各種初期設定をした後、Rescale上に持続的クラスタ(Persistent Cluster)を起動する。通常Rescaleでは、各ジョブごとに新規でクラスタを起動し、ジョブが完了すると自動的にクラスタを削除する。一方持続的クラスタを使用すると、ジョブ完了後もクラスタが残り、別のジョブを投入して実行することができる。最適化のようにジョブを連続して実行する場合は、持続的クラスタを使用することで、<a href="https://medium.com/@takahisa.shiratori/%E8%A8%AD%E8%A8%88%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%A8%E3%83%A2%E3%83%87%E3%83%AB%E3%83%99%E3%83%BC%E3%82%B9%E9%96%8B%E7%99%BA%E3%81%AB%E5%90%91%E3%81%91%E3%81%9Fpersistent-cluster%E3%81%AEapi%E6%93%8D%E4%BD%9C-ddf7ec1bb177">クラスタの起動と削除にかかる時間を節約することができる</a></p><p>持続的クラスタの起動後、ベイズ最適化のアルゴリズムがJupyter Notebook上で動き、CFDの実行パラメータ（この例の場合はdamBreakのダムの縦横サイズ）を決定する。Jupyter NotebookからRescaleのAPIを実行して、決定したパラメータをジョブに引き渡して実行する。ジョブ完了後に、ジョブの出力の中から目的変数（この例の場合は水滴の最高到達点）が取得され、次のジョブのパラメータを決定する際に使用される。RescaleにジョブをAPIで投入する際は、複数のAPIリクエストを送る必要があるため、Notebook内ではまず各リクエストを1つずつ実行して、1回ジョブを投入するようになっている。その後それらの処理を1つの関数としてまとめ、ベイズ最適化の目的関数として使用する</p><p>最後に、持続的クラスタをAPIで削除する</p><h3>必要なもの</h3><h4>(1) Rescale の API キー</h4><p>Rescaleにまだサインアップしていない場合は、<a href="https://www.rescale.com/">こちら</a>からサインアップする。ログイン後、<a href="https://docs.rescale.com/articles/rest-api/">こちら</a>の手順にしたがってAPIキーを作成する。APIキーを作成できない場合は、販売代理店またはRescaleサポートに依頼する</p><h4>(2) Jupyter Notebook 実行環境</h4><p>手軽な方法としては、Googleアカウントにログインした状態で<a href="https://github.com/TakahisaShiratori/bayesianopt-openfoam-rescale/blob/master/damBreak_with_rescale_persistent_cluster.ipynb">こちら</a>のNotebook上部の Open in Colab ボタンをクリックすると、Google Colaboratoryで実行できる</p><h3>実行手順</h3><p>ここからは、各コードブロックの内容を説明する形で、実行手順を記載する</p><pre>rescale_api_key = “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”</pre><pre># Allowed values for platform are “platform.rescale.com”, “platform.rescale.jp” and “kr.rescale.com”</pre><pre>platform = “platform.rescale.jp”</pre><p>このNotebookを実行するにあたってユーザが設定する変数は、上記のコードブロックの通りrescale_api_keyとplatformの2つである。rescale_api_keyは、「必要なもの」の項で示した方法で取得する。platformは、Rescaleにログインしている際のURLで確認する</p><pre>token_in_header = &quot;Token &quot; + rescale_api_key</pre><pre>if platform == &quot;platform.rescale.com&quot;:<br>  template_jobid = &quot;XPEsQc&quot;<br>  print(&quot;Template Job ID: &quot; + template_jobid)<br>elif platform == &quot;platform.rescale.jp&quot;:<br>  template_jobid = &quot;GHVjd&quot;<br>  print(&quot;Template Job ID: &quot; + template_jobid)<br>elif platform == &quot;kr.rescale.com&quot;:<br>  template_jobid = &quot;TRJOc&quot;<br>  print(&quot;Template Job ID: &quot; + template_jobid)<br>else:<br>  print(&quot;Allowed values for platform are platform.rescale.com, platform.rescale.jp and kr.rescale.com&quot;)</pre><p>ここでは主に、platformの入力値に応じて適切なジョブIDをtemplate_jobidに代入する。この最適化フローでテンプレートとして使用するジョブを、各プラットフォームで下表のように公開している。Rescaleにログインした状態で表中のリンクをクリックすると、テンプレートジョブの設定を見ることができる</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0bdef3b9cad9c08a1405e401adff9a25/href">https://medium.com/media/0bdef3b9cad9c08a1405e401adff9a25/href</a></iframe><pre>cluster_configuration = {<br>  &quot;name&quot;: &quot;OpenFOAM 6 Persistent Cluster&quot;,<br>  &quot;hardware&quot;: {<br>    &quot;coresPerSlot&quot;: 1,<br>    &quot;slots&quot;: 1,<br>    &quot;coreType&quot;: &quot;emerald&quot;,<br>    &quot;walltime&quot;: 5<br>  },<br>  &quot;installedAnalyses&quot;: [<br>    {<br>      &quot;analysis&quot;: {<br>        &quot;code&quot;: &quot;openfoam&quot;,<br>        &quot;version&quot;: &quot;6-intelmpi&quot;<br>      }<br>    }<br>  ],<br>  &quot;runLowPriority&quot;: True<br>}</pre><p>起動する持続的クラスタの設定をcluster_configurationに代入する。今回はコアタイプEmerald, コア数は1に設定する。またこの例ではWalltimeを5時間に設定し、持続的クラスタを削除し忘れた場合でも5時間で自動削除されるようにしている。ただしWalltimeに到達すると、最適化ワークフローの実行途中であってもクラスタが自動削除される</p><pre>import json<br>import requests<br>import time</pre><pre># Create Cluster<br>raw_reply = requests.post(<br>  &quot;https://&quot; + platform + &quot;/api/v2/clusters/&quot;, <br>  headers={&quot;Authorization&quot;: token_in_header}, <br>  json=cluster_configuration<br>)<br>created_cluster = json.loads(raw_reply.text)<br>print(&quot;Cluster ID: &quot; + created_cluster[&quot;id&quot;])</pre><pre># Start Cluster<br>requests.post(<br>  &quot;https://&quot; + platform + &quot;/api/v2/clusters/&quot; + created_cluster[&quot;id&quot;] + &quot;/start/&quot;,<br>  headers={&quot;Authorization&quot;: token_in_header}<br>)</pre><pre>time.sleep(10)</pre><pre># Get the Cluster&#39;s Status<br>raw_reply = requests.get(<br>  &quot;https://&quot; + platform + &quot;/api/v2/clusters/&quot; + created_cluster[&quot;id&quot;] + &quot;/statuses/&quot;,<br>  headers={&quot;Authorization&quot;: token_in_header}<br>)<br>cluster_statuses = json.loads(raw_reply.text)<br>print(&quot;Cluster ID: &quot; + created_cluster[&quot;id&quot;] + &quot;, Status date: &quot; + cluster_statuses[&quot;results&quot;][0][&quot;statusDate&quot;] + &quot;, Status: &quot; + cluster_statuses[&quot;results&quot;][0][&quot;status&quot;])</pre><p>持続的クラスタを起動するには、クラスタのCreateとStartの計2回のAPIリクエストが必要である。Sleepで間を置いた後にクラスタのステータスを取得することで、クラスタの起動が始まったことを確認している</p><pre>def get_a_specific_job(jobid):<br>  raw_reply = requests.get(<br>    &quot;https://&quot; + platform + &quot;/api/v2/jobs/&quot; + jobid + &quot;/&quot;, <br>    headers={&quot;Authorization&quot;: token_in_header},<br>  )<br>  job_configuration = json.loads(raw_reply.text)<br>  return job_configuration</pre><pre>template_job_configuration = get_a_specific_job(template_jobid)<br>print(template_job_configuration)</pre><p>テンプレートジョブの設定を取得し、template_job_configurationに代入する</p><pre>import numpy as np</pre><pre>def set_width_height(input_job_configuration, cluster_configuration, width, height):<br>  output_job_configuration = input_job_configuration.copy()<br>  output_job_configuration[&quot;name&quot;] = &quot;OpenFOAM 6 damBreak, width = {width}, height = {height}&quot;.format(<br>    width=str(width),<br>    height=str(height)<br>  )<br>  output_job_configuration[&quot;jobanalyses&quot;][0][&quot;command&quot;] = &quot;sed -ie s/val_width/{width}/ blockMeshDict.template\nsed -ie s/val_height/{height}/ blockMeshDict.template\n\ncp blockMeshDict.template damBreak/system/blockMeshDict\n\ncd damBreak\n./Allrun\n\ncd ..\npython postprocess.py&quot;.format(<br>    width=str(width),<br>    height=str(height)<br>  )<br>  output_job_configuration[&quot;jobanalyses&quot;][0][&quot;hardware&quot;] = cluster_configuration[&quot;hardware&quot;].copy()<br>  output_job_configuration[&quot;isLowPriority&quot;] = cluster_configuration[&quot;runLowPriority&quot;]<br>  return output_job_configuration</pre><pre># width  = 1.8<br># height = 0.3333<br>x = np.array([[1.8,0.3333]])<br>width  = x[:,0][0]<br>height = x[:,1][0]<br>submit_job_configuration = set_width_height(template_job_configuration, cluster_configuration, width, height)<br>print(submit_job_configuration)</pre><p>テンプレートジョブでは, sedコマンドでOpenFOAMの設定ファイル(blockMeshDict)の一部文字列を置換することで、CFDのパラメータを設定している。上記コードブロックでは、例として、ダムの高さ 1.8, 幅 0.333 をパラメータとして引き渡している。ジョブの設定はsubmit_job_configurationに代入される</p><pre>def create_a_job(job_configuration):<br>  raw_reply = requests.post(<br>    &quot;https://&quot; + platform + &quot;/api/v2/jobs/&quot;,<br>    headers={&quot;Authorization&quot;: token_in_header},<br>    json=job_configuration<br>  )<br>  created_job = json.loads(raw_reply.text)<br>  return created_job</pre><pre>created_job = create_a_job(submit_job_configuration)<br>print(&quot;Job ID: &quot; + created_job[&quot;id&quot;])</pre><p>ジョブ設定submit_job_configurationに基づき、Rescaleにジョブを作成する。上記コードブロックを実行した段階で、Rescaleにログインしてジョブ一覧を確認すると、新しくジョブが作成されたことがわかる。ただしこの段階ではまだジョブは投入されていない</p><pre>def submit_a_saved_job(jobid, clusterid):<br>  submit_configuration = {}<br>  submit_configuration[&quot;id&quot;]     = jobid<br>  submit_configuration[&quot;submit&quot;] = True<br>  raw_reply = requests.post(<br>    &quot;https://&quot; + platform + &quot;/api/v2/clusters/&quot; + clusterid + &quot;/jobs/&quot;,<br>    headers={&quot;Authorization&quot;: token_in_header},<br>    json=submit_configuration<br>  )<br>  submitted_job = json.loads(raw_reply.text)<br>  return submitted_job</pre><pre>submitted_job = submit_a_saved_job(created_job[&quot;id&quot;], created_cluster[&quot;id&quot;])<br>print(&quot;Job &quot; + submitted_job[&quot;id&quot;] + &quot; is submitted to the cluster &quot; + created_cluster[&quot;id&quot;])</pre><p>作成したジョブを投入する。上記コードブロックを実行後にジョブを確認すると、ジョブが実行されていることを確認できる</p><pre>def status_polling(jobid):<br>  sleep_secs = 5<br>  while True:<br>    raw_reply = requests.get(<br>      &quot;https://&quot; + platform + &quot;/api/v2/jobs/&quot; + jobid + &quot;/statuses/&quot;, <br>      headers={&quot;Authorization&quot;: token_in_header}<br>    )<br>    job_statuses = json.loads(raw_reply.text)<br>    if job_statuses[&quot;results&quot;][0][&quot;status&quot;] == &quot;Completed&quot;:<br>      break<br>    time.sleep(sleep_secs)</pre><pre>status_polling(submitted_job[&quot;id&quot;])<br>print(&quot;Job &quot; + submitted_job[&quot;id&quot;] + &quot; is Completed&quot;)</pre><p>投入したジョブのステータスを5秒おきに確認する。関数status_pollingは、ジョブが完了したことを確認できたら終了する</p><pre>def get_dembreak_result(jobid):<br>  can_break = False<br>  url = &quot;https://&quot; + platform + &quot;/api/v2/jobs/&quot; + jobid + &quot;/files/&quot;</pre><pre>while can_break == False:</pre><pre>raw_reply = requests.get(<br>      url, <br>      headers={&quot;Authorization&quot;: token_in_header}<br>    )<br>    output_files = json.loads(raw_reply.text)</pre><pre>for result in output_files[&quot;results&quot;]:<br>      if result[&quot;name&quot;] == &quot;result.txt&quot;:<br>        file_id = result[&quot;id&quot;]<br>        can_break = True<br>        break</pre><pre>url = output_files[&quot;next&quot;]</pre><pre>raw_reply = requests.get(<br>    &quot;https://&quot; + platform + &quot;/api/v2/files/&quot; + file_id + &quot;/lines/&quot;, <br>    headers={&quot;Authorization&quot;: token_in_header}<br>  )<br>  file_lines = json.loads(raw_reply.text)<br>  return float(file_lines[&quot;lines&quot;][0])</pre><pre>dembreak_result = get_dembreak_result(submitted_job[&quot;id&quot;])<br>print(dembreak_result)</pre><pre>dembreak_result_numpy = np.array([dembreak_result])<br>print(dembreak_result_numpy)</pre><p>今回実行したジョブでは、最適化の目的変数である水滴の最高到達点の座標を, result.txt というファイルに出力するようにしている。上記のコードブロックでは、まず result.txt のファイルIDを取得し、その後ファイルの中身を取得している。今回の、高さ 1.8 幅 0.333 の条件では, 0.418563 が解として返る</p><pre>def rescale_damBreak(x):<br>  width  = x[:,0][0]<br>  height = x[:,1][0]</pre><pre>submit_job_configuration = set_width_height(template_job_configuration, cluster_configuration, width, height)<br>  created_job = create_a_job(submit_job_configuration)<br>  submitted_job = submit_a_saved_job(created_job[&quot;id&quot;], created_cluster[&quot;id&quot;])<br>  status_polling(submitted_job[&quot;id&quot;])<br>  dembreak_result = get_dembreak_result(submitted_job[&quot;id&quot;])<br>  dembreak_result_numpy = np.array([dembreak_result])</pre><pre>return dembreak_result_numpy</pre><pre>x = np.array([[1.8,0.3333]])<br>rescale_damBreak(x)</pre><p>最適化を実行する時には、目的関数がPythonの1つの関数として定義されている必要があるため、関数rescale_damBreakとしてこれまでの一連の流れをまとめる。再度1.8（高さ）と0.333（幅）を関数に入力すると, 0.418563 が出力として返ってくることを確認できる</p><pre>%%bash<br>pip install GPy<br>pip install gpyopt<br>pip install pyDOE</pre><p>最適化を実行するのに先立ち、必要なパッケージをpipでインストールする</p><pre>bounds =[{&#39;name&#39;: &#39;w&#39;, &#39;type&#39;: &#39;continuous&#39;, &#39;domain&#39;: (1.7, 2.1)},<br>         {&#39;name&#39;: &#39;h&#39;, &#39;type&#39;: &#39;continuous&#39;, &#39;domain&#39;: (0.1, 0.8)}]</pre><p>最適化における、パラメータの探索範囲を設定する。幅(w)は 1.7 から 2.1, 高さ(h)は 0.1 から 0.8 の範囲で探索する</p><pre>import GPyOpt<br>from numpy.random import seed</pre><pre>seed(1)</pre><pre>myProblem = GPyOpt.methods.BayesianOptimization(rescale_damBreak,<br>  domain=bounds,<br>  initial_design_numdata=5,<br>  initial_design_type=&quot;latin&quot;,<br>  maximize=True,<br>  verbosity=True)</pre><pre>max_iter = 25<br>myProblem.run_optimization(max_iter)</pre><p>最適化を実行する。初期計算(initial_design_numdata)として5条件、繰り返し(max_iter)で最大25条件のCFDが実行されるため、Rescale上で計30ジョブが実行される。このコードブロックの実行には、通常30分程度を要する</p><pre>%matplotlib inline <br>myProblem.plot_convergence()</pre><p>最終的な解に収束するまでの過程を、グラフで表示する</p><pre>print(myProblem.x_opt, myProblem.fx_opt)</pre><p>得られた解を表示する。今回得られた解におけるダムの幅、高さ、液滴の到達点が表示される</p><pre>myProblem.plot_acquisition()</pre><p>事後平均、事後標準偏差、および獲得関数を、パラメータ空間（このケースではダムの高さと幅）での分布として表示できる</p><pre><em># Shutdown the Cluster</em><br>requests.post(<br>  &quot;https://&quot; + platform + &quot;/api/v2/clusters/&quot; + created_cluster[&quot;id&quot;] + &quot;/shutdown/&quot;,<br>  headers={&quot;Authorization&quot;: token_in_header}<br>)<br><br>time.sleep(10)<br><br><em># Get the Cluster&#39;s Status</em><br>raw_reply = requests.get(<br>  &quot;https://&quot; + platform + &quot;/api/v2/clusters/&quot; + created_cluster[&quot;id&quot;] + &quot;/statuses/&quot;,<br>  headers={&quot;Authorization&quot;: token_in_header}<br>)<br>cluster_statuses = json.loads(raw_reply.text)<br>print(&quot;Cluster ID: &quot; + created_cluster[&quot;id&quot;] + &quot;, Status date: &quot; + cluster_statuses[&quot;results&quot;][0][&quot;statusDate&quot;] + &quot;, Status: &quot; + cluster_statuses[&quot;results&quot;][0][&quot;status&quot;])</pre><p>最後に、起動させていた持続的クラスタを終了させる</p><h3>関連する過去の記事</h3><p><a href="http://blog.serverworks.co.jp/tech/2018/01/17/sagemaker-rescale/">Amazon SageMaker（というかJupyter Notebook）からRescaleを操作する — サーバーワークスエンジニアブログ</a></p><p><a href="https://medium.com/@takahisa.shiratori/%E8%A8%AD%E8%A8%88%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%A8%E3%83%A2%E3%83%87%E3%83%AB%E3%83%99%E3%83%BC%E3%82%B9%E9%96%8B%E7%99%BA%E3%81%AB%E5%90%91%E3%81%91%E3%81%9Fpersistent-cluster%E3%81%AEapi%E6%93%8D%E4%BD%9C-ddf7ec1bb177">設計最適化とモデルベース開発に向けたPersistent ClusterのAPI操作 — Takahisa Shiratori — Medium</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=992e260af690" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Google Cloud ShellでOpenFOAM(v7, Docker)を動かしてみた]]></title>
            <link>https://medium.com/@takashiratori/google-cloud-shell%E3%81%A7openfoam-v7-docker-%E3%82%92%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F-ef3a2c3e14c3?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/ef3a2c3e14c3</guid>
            <category><![CDATA[gcp]]></category>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[日本語]]></category>
            <category><![CDATA[google-cloud-shell]]></category>
            <category><![CDATA[openfoam]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Tue, 31 Mar 2020 03:01:39 GMT</pubDate>
            <atom:updated>2020-03-31T03:01:39.525Z</atom:updated>
            <content:encoded><![CDATA[<p>本記事は、Qiitaで公開していた記事（最終更新 2019年9月11日）を移行したものです。内容は当時のものです</p><h3>はじめに</h3><p><a href="https://cloud.google.com/shell/docs/">Google Cloud Shell</a>はGoogle Cloud Platform (GCP)の機能の一つで、ブラウザから簡単に使えるshell環境です。GCPの管理画面(Google Cloud Console)にログインし右上のボタンをクリックすると、ブラウザ下部にぽこっと立ち上がります。<a href="https://cloud.google.com/shell/pricing">無料で使える</a>ようです。DockerやGitなどもプリインストースされています</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iHYBJZ9yT1W62gkizjflEA.png" /></figure><p>この記事では、OpenFOAM v7を、公式Dockerイメージを使ってCloud Shell上で動かしてみます。基本的にドキュメント(<a href="https://openfoam.org/download/7-linux/">Download v7 | Linux</a>)の手順に従い、OpenFOAMのチュートリアルの1つであるpitzDaily(<a href="https://youtu.be/f6U8fdNqsec">YouTube</a>, <a href="https://github.com/OpenFOAM/OpenFOAM-7/tree/master/tutorials/incompressible/simpleFoam/pitzDaily">GitHub</a>)を実行します</p><h3>やってみる</h3><p>Cloud Shellを立ち上げると、こんな感じのメッセージが表示され、コマンド入力待ちになります</p><pre>Welcome to Cloud Shell! Type “help” to get started.<br>Your Cloud Platform project in this session is set to XXXXX-XXXXX-XXXXXX.<br>Use “gcloud config set project [PROJECT_ID]” to change to a different project.<br>takahisa_shiratori@cloudshell:~ (XXXXX-XXXXX-XXXXXX)$</pre><p>DockerはCloud Shell環境にプリインストールされているので、<a href="https://openfoam.org/download/7-linux/">ドキュメント</a>中のStep 4: Installing openfoam7-linuxから始めれば良いです。まずはDockerコンテナを立ち上げるWrapper Scriptを以下のコマンドで取得します</p><pre>takahisa_shiratori@cloudshell:~ (XXXXX-XXXXX-XXXXXX)$ sudo sh -c “wget <a href="http://dl.openfoam.org/docker/openfoam7-linux">http://dl.openfoam.org/docker/openfoam7-linux</a> -O /usr/bin/openfoam7-linux”<br> — 2019–08–23 13:14:58 — http://dl.openfoam.org/docker/openfoam7-linux<br>Resolving dl.openfoam.org (dl.openfoam.org)… 52.208.208.42<br>Connecting to dl.openfoam.org (dl.openfoam.org)|52.208.208.42|:80… connected.<br>HTTP request sent, awaiting response… 200 OK<br>Length: 4893 (4.8K)<br>Saving to: ‘/usr/bin/openfoam7-linux’</pre><pre>/usr/bin/openfoam7-linux 100%[===========================================================================================&gt;] 4.78K — .-KB/s in 0s</pre><pre>2019–08–23 13:14:58 (545 MB/s) — ‘/usr/bin/openfoam7-linux’ saved [4893/4893]</pre><pre>takahisa_shiratori@cloudshell:~ (XXXXX-XXXXX-XXXXXX)$ sudo chmod 755 /usr/bin/openfoam7-linux<br>takahisa_shiratori@cloudshell:~ (XXXXX-XXXXX-XXXXXX)$</pre><p>OpenFOAM公式Dockerコンテナでは、コンテナ内での解析の出力ファイルをホスト側（今回の例ではCloud Shell環境）に保存します。それらのファイルが保存されるディレクトリを作成してcdします</p><pre>takahisa_shiratori@cloudshell:~ (XXXXX-XXXXX-XXXXXX)$ mkdir -p $HOME/OpenFOAM/${USER}-7<br>takahisa_shiratori@cloudshell:~ (XXXXX-XXXXX-XXXXXX)$ cd $HOME/OpenFOAM/${USER}-7<br>takahisa_shiratori@cloudshell:~/OpenFOAM/takahisa_shiratori-7 (XXXXX-XXXXX-XXXXXX)$</pre><p>openfoam7-linuxコマンドで、Wrapper Scriptが実行されます。Dockerイメージがダウンロードされ、コンテナ内のshellにログインした状態になります</p><pre>takahisa_shiratori@cloudshell:~/OpenFOAM/takahisa_shiratori-7 (XXXXX-XXXXX-XXXXXX)$ openfoam7-linux<br>Launching /usr/bin/openfoam7-linux<br>User: “takahisa_shiratori” (ID 1000, group ID 1000)<br>Unable to find image ‘openfoam/openfoam7-paraview56:latest’ locally<br>latest: Pulling from openfoam/openfoam7-paraview56<br>32802c0cfa4d: Pull complete<br>da1315cffa03: Pull complete<br>fa83472a3562: Pull complete<br>f85999a86bef: Pull complete<br>7a79eea169fb: Pull complete<br>df31dfdb41f5: Pull complete<br>36d2fc2d0429: Pull complete<br>c2a8fd74724a: Pull complete<br>130d3370750a: Pull complete<br>68d2d0e4e269: Pull complete<br>89a879d07858: Pull complete<br>65f91bb3b40a: Pull complete<br>949b9028c2e9: Pull complete<br>af7f092ba88c: Pull complete<br>54dcc184127f: Pull complete<br>883f18e49a8a: Pull complete<br>7c4f480985b9: Pull complete<br>Digest: sha256:f5183a5c4625f3302b5950d132d42eb0ac62500cc83b094bca4f887343219945<br>Status: Downloaded newer image for openfoam/openfoam7-paraview56:latest<br>Welcome to the OpenFOAM v7 Docker Image</pre><pre>Provides bash terminal with OpenFOAM 7 and ParaView 5.6.0</pre><pre>Produced and maintained by CFD Direct (https://cfd.direct), on behalf of the<br>OpenFOAM Foundation (https://openfoam.org), the owner and distributor of<br>OpenFOAM as free, open source software under the General Public Licence v3.</pre><pre>Further Resources:<br>* OpenFOAM User Guide: <a href="https://cfd.direct/openfoam/user-guide">https://cfd.direct/openfoam/user-guide</a><br>* C++ Source Guide: <a href="https://cpp.openfoam.org/">https://cpp.openfoam.org</a><br>* OpenFOAM Training: <a href="https://cfd.direct/openfoam-training">https://cfd.direct/openfoam-training</a><br>* Running in the Cloud: <a href="https://cfd.direct/cloud">https://cfd.direct/cloud</a><br>* Issue (Bug) Reporting: <a href="https://bugs.openfoam.org/">https://bugs.openfoam.org</a><br>* Subscribe to Newsletter: <a href="https://cfd.direct/news">https://cfd.direct/news</a><br>* Contributors to OpenFOAM: <a href="https://openfoam.org/dev/contributors">https://openfoam.org/dev/contributors</a></pre><pre>f7eb7dad7e17: ~&gt;&gt;</pre><p>OpenFOAMの解析を実行するディレクトリを作成し、Tutorialに必要なファイルをその配下にcpしてきます</p><pre>f7eb7dad7e17: ~&gt;&gt; mkdir -p $FOAM_RUN<br>f7eb7dad7e17: ~&gt;&gt; cd $FOAM_RUN <br>f7eb7dad7e17: run&gt;&gt; cp -r $FOAM_TUTORIALS/incompressible/simpleFoam/pitzDaily .<br>f7eb7dad7e17: run&gt;&gt; cd pitzDaily<br>f7eb7dad7e17: pitzDaily&gt;&gt;</pre><p>あとはOpenFOAMのコマンドであるblockMesh, simpleFoamを実行すると解析が開始されます</p><pre>50aad391a91a: pitzDaily&gt;&gt; blockMesh<br>/* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -*\<br> ========= |<br> \\ / F ield | OpenFOAM: The Open Source CFD Toolbox<br> \\ / O peration | Website: <a href="https://openfoam.org/">https://openfoam.org</a><br> \\ / A nd | Version: 7<br> \\/ M anipulation |<br>\* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -*/<br>Build : 7–109ba3c8d53a<br>Exec : blockMesh<br>Date : Aug 23 2019<br>Time : 05:31:27<br>Host : “50aad391a91a”<br>PID : 196<br>I/O : uncollated<br>Case : /home/openfoam/run/pitzDaily<br>nProcs : 1<br>sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).<br>fileModificationChecking : Monitoring run-time modified files using timeStampMaster (fileModificationSkew 10)<br>allowSystemOperations : Allowing user-supplied system call operations</pre><pre>// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //<br>Create time<br>（以下略）</pre><p>===</p><pre>50aad391a91a: pitzDaily&gt;&gt; simpleFoam<br>/* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -*\<br> ========= |<br> \\ / F ield | OpenFOAM: The Open Source CFD Toolbox<br> \\ / O peration | Website: <a href="https://openfoam.org/">https://openfoam.org</a><br> \\ / A nd | Version: 7<br> \\/ M anipulation |<br>\* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -*/<br>Build : 7–109ba3c8d53a<br>Exec : simpleFoam<br>Date : Aug 23 2019<br>Time : 05:31:42<br>Host : “50aad391a91a”<br>PID : 197<br>I/O : uncollated<br>Case : /home/openfoam/run/pitzDaily<br>nProcs : 1<br>sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).<br>fileModificationChecking : Monitoring run-time modified files using timeStampMaster (fileModificationSkew 10)<br>allowSystemOperations : Allowing user-supplied system call operations</pre><pre>// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //<br>Create time<br>（以下略）</pre><p>さすがにparaFoamでの可視化はできませんでした</p><pre>12a2b92403f6: pitzDaily&gt;&gt; paraFoam<br>Created temporary ‘pitzDaily.OpenFOAM’<br>QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to ‘/tmp/runtime-openfoam’<br>qt.qpa.screen: QXcbConnection: Could not connect to display<br>Could not connect to any X display.<br>12a2b92403f6: pitzDaily&gt;&gt;</pre><p>最終Itertationの計算結果は、現在の作業ディレクトリの288配下に保存されています</p><pre>12a2b92403f6: pitzDaily&gt;&gt; ls<br>0 100 200 288 constant postProcessing system<br>12a2b92403f6: pitzDaily&gt;&gt; ls 288/<br>U epsilon k nut p phi uniform<br>12a2b92403f6: pitzDaily&gt;&gt; cat 288/U<br>/* — — — — — — — — — — — — — — — — *- C++ -* — — — — — — — — — — — — — — — — — *\<br> ========= |<br> \\ / F ield | OpenFOAM: The Open Source CFD Toolbox<br> \\ / O peration | Website: <a href="https://openfoam.org/">https://openfoam.org</a><br> \\ / A nd | Version: 7<br> \\/ M anipulation |<br>\* — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — -*/<br>FoamFile<br>{<br> version 2.0;<br> format ascii;<br> class volVectorField;<br> location “288”;<br> object U;<br>}<br>// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //</pre><pre>dimensions [0 1 -1 0 0 0 0];</pre><pre>internalField nonuniform List&lt;vector&gt;<br>12225<br>(<br>(9.85698 -0.886449 0)<br>(9.66665 -0.740747 0)<br>(9.45574 -0.429483 0)<br>(9.22457 -0.222216 0)<br>(9.00656 -0.106462 0)</pre><pre>（以下略）</pre><p>exitでCloud Shell環境に戻ります</p><pre>439060b9e712: pitzDaily&gt;&gt; exit<br>exit<br>takahisa_shiratori@cloudshell:~/OpenFOAM/takahisa_shiratori-7 (XXXXX-XXXXX-XXXXXX)$</pre><p>計算結果をダウンロードしたい場合は、Google Cloud Consoleからダウンロードできます。OpenFOAM公式Dockerイメージでは、コンテナで計算した結果の出力もホスト側に保存されます。よって、必要なファイルの、Cloud Shell環境におけるフルパスを指定すればダウンロードできます</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Xw53HImmlF-dh_ErgK127w.png" /></figure><p>ちなみに、GCPには<a href="https://cloud.google.com/console-app/">スマートフォンアプリ</a>があります。Cloud Shellも利用できるため、スマートフォンからOpenFOAMを動かす環境を簡単に作ることができました</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c9rWElsq4bQqedgyEmkLZw.jpeg" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ef3a2c3e14c3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[機械学習で新幹線車両の写真を分類する on ABEJA Platform]]></title>
            <link>https://medium.com/@takashiratori/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%81%A7%E6%96%B0%E5%B9%B9%E7%B7%9A%E8%BB%8A%E4%B8%A1%E3%81%AE%E5%86%99%E7%9C%9F%E3%82%92%E5%88%86%E9%A1%9E%E3%81%99%E3%82%8B-on-abeja-platform-23620878ca55?source=rss-ddc6e69b24f9------2</link>
            <guid isPermaLink="false">https://medium.com/p/23620878ca55</guid>
            <category><![CDATA[日本語]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[新幹線]]></category>
            <category><![CDATA[abeja-platform]]></category>
            <category><![CDATA[機械学習]]></category>
            <dc:creator><![CDATA[Takahisa Shiratori]]></dc:creator>
            <pubDate>Mon, 30 Mar 2020 15:02:14 GMT</pubDate>
            <atom:updated>2020-03-30T15:02:14.671Z</atom:updated>
            <content:encoded><![CDATA[<p>本記事は、Qiitaで公開していた記事（最終更新 2019年1月31日）を移行したものです。内容は当時のものです</p><p>本記事では、<a href="https://www.jreast.co.jp/train/shinkan/e5.html">E5系</a>と<a href="https://railway.jr-central.co.jp/train/shinkansen/detail_01_01/">N700系</a>の写真を機械学習で分類してみます（ゆくゆくはもっと多くの車種に対応できるようにしたいのですが、ひとまずやりやすそうなこの2車種にします）。クローラを使用してインターネット上から両車種の画像を集め、<a href="https://abejainc.com/platform/ja/">ABEJA Platform</a>にて学習（たくさん画像を読み込ませてE5系とN700系を覚えさせる）と推論（車両の写真を渡してE5系かN700系かを判断させる）を行います</p><p># 参考にした資料等</p><p>- <a href="https://developers.abeja.io/">ABEJA Platform Developers</a></p><p>- <a href="https://tech-blog.abeja.asia/entry/santa-recognition-from-scratch">サンタクロースとサンタコスを見分けるDeep Learningモデルをサービス化してみた — ABEJA Arts Blog</a></p><h3>画像の収集</h3><p><a href="https://pypi.org/project/icrawler/">icrawler</a>を使用して、インターネット上で公開されているE5系とN700系の画像を集めてきます。使用したコードを<a href="https://gist.github.com/TakahisaShiratori/61f5d7420913b0c7957fd699b623a1ac#file-icrawler-ipynb">こちら</a>に公開しておきます。これを実行することにより、image_shinkansen/E5系とimage_shinkansen/N700系のディレクトリに両車種の画像が保存されます。私が実行した時点では、253枚のE5系の画像と、381枚のN700系の画像を得ることができました</p><p>ただしここで得られた画像には</p><ul><li>H5系や700系の画像</li><li>複数の車種の新幹線が写っている画像</li><li>新幹線の内装の画像</li><li>鉄道模型や玩具などの画像</li><li>新幹線と全く関係のなさそうな画像</li></ul><p>などが含まれています。得られた画像を全て目視で確認し、これらの画像は取り除きました。その結果、E5系の画像は92枚、N700系の画像は100枚となりました。なおN700系の画像には、G・F編成(N700A)とS・R編成（みずほ・さくら、8両編成）の画像も含めています</p><h3>画像のアップロードとデータセットの登録</h3><p><a href="https://developers.abeja.io/cli/">ABEJA Platform CLI</a>を使用して、画像のアップロードとデータセットとしての登録を行います。ABEJA Platform Developersに載っている<a href="https://developers.abeja.io/getting-started-guide/training-model/training-and-model/">犬と猫の画像を分類するチュートリアル</a>と同じ手順を使います</p><h4>Channelの作成</h4><pre>$ abeja datalake create-channel — name “shinkansen” — description “this is image channel of E5 and N700”</pre><p>返り値の中の”channel_id”は後で使うので控えておきます</p><h4>画像のアップロード</h4><p>E5系の画像をアップロードします</p><pre>$ cd image_shinkansen/E5系/<br>$ abeja datalake upload — channel_id ${channel_id} — metadata label_id:1 — recursive .</pre><p>N700系の画像をアップロードします</p><pre>$ cd ../N700系/<br>$ abeja datalake upload — channel_id ${channel_id} — metadata label_id:2 — recursive .</pre><h4>データセットの登録</h4><p>アップロードした画像をデータセットとして登録します。まずはデータセットの設定をJSON形式のファイルに記述します</p><pre>$ cd ..<br>$ vim e5_n700_dataset.json<br>$ cat e5_n700_dataset.json<br>{<br>  &quot;categories&quot;: [<br>    {<br>      &quot;labels&quot;: [<br>        {<br>          &quot;label_id&quot;: 1,<br>          &quot;label&quot;: &quot;E5&quot;<br>        },<br>        {<br>          &quot;label_id&quot;: 2,<br>          &quot;label&quot;: &quot;N700&quot;<br>        },<br>        {<br>          &quot;label_id&quot;: 3,<br>          &quot;label&quot;: &quot;others&quot;<br>        }<br>      ],<br>      &quot;category_id&quot;: 1,<br>      &quot;name&quot;: &quot;e5_n700&quot;<br>    }<br>  ]<br>}</pre><p>次にデータセットを作成します。返り値の中の”dataset_id”は後で使うので控えておきます</p><pre>$ abeja dataset create-dataset — name e5_n700 — type classification — props e5_n700_dataset.json</pre><p>最後に、DataLakeに保存してある画像をデータセットとして登録します</p><pre>$ abeja dataset import-from-datalake — channel_id ${channel_id} — dataset_id ${dataset_id} — label-metadata-name label_id</pre><p>データセットとして登録した画像は、ABEJA Platformにログインして一覧で確認することができます</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TMCpklCS3xXCaJJC-HqZKQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BNt4535VnFkdiPYlRcWOSg.png" /></figure><p>（データセットの画像部分には、ぼかしを入れています）</p><h3>学習・推論</h3><p>ここから、ABEJA Platformにログインして学習と推論を行います。</p><h4>Job Definition の作成</h4><p>Job Definition（ジョブ定義）を作成します。ジョブ定義の一覧の画面で “+ Create Training Job Definition” をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gzsRNmhxqw7srLrwE8IdYQ.png" /></figure><p>Training Job Definitionの名前を入力する画面になるので、適当に名前を入力します。今回は “shinkansen_classifier” という名前にしました</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dr39Jp_lRCUKNw9M73Pd6Q.png" /></figure><p>次に、作成したJob Definitionに対して、 “Create Version” をクリックしてバージョンを作成します</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QKX8Zn5PsmpKR4_0fxewpw.png" /></figure><p>Training Job Definitionのバージョン設定をする画面に遷移します</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5gP_2gMzFr2DkEHPjO04og.png" /></figure><p>ここでは各入力値を以下のように設定します</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7c64e3bc2be46b3ecbb951f21992c5bd/href">https://medium.com/media/7c64e3bc2be46b3ecbb951f21992c5bd/href</a></iframe><h4>Training Jobの作成と実行</h4><p>Training Job（学習ジョブ）を作成して実行します。まずはJob Definittionsの一覧でJobsをクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UNynIJRNO8ybOHFw1XxdMw.png" /></figure><p>Training Jobの一覧が表示されるので”+ Create Training Job”をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nIvQ2_dE8M4HnOarmMNQnA.png" /></figure><p>Training Jobの設定をする画面に遷移します</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_Tp615N6mxb7cdkJFOVQ_A.png" /></figure><p>ここでは各入力値を以下のように設定します</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0c6b3beea502c79d398bb5e1b1405406/href">https://medium.com/media/0c6b3beea502c79d398bb5e1b1405406/href</a></iframe><p>学習ジョブが開始され、以下のように現在のステータスを確認できるようになります</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G56o7h3_PztwEcMOYlqskA.png" /></figure><h4>推論モデルのエンドポイントの作成</h4><p>学習ジョブが終了したら、E5系とN700系を見分ける脳みそができたことになります。次に、推論モデルのエンドポイントを作成します。これは、できた脳みそにE5系やN700系の画像を渡し、「これはE5系だ」「これはN700系だ」と返すようにする受け口をつくることに相当します</p><p>推論モデルのエンドポイントを作成するには、まず、Modelsの一覧画面で”+ Create Models”をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FV9c7ziIxSwiQb1JPgFIeA.png" /></figure><p>新規作成するモデル（推論モデル）の設定画面が開きます</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*epztDIGOQTAdWmYL1FRDWA.png" /></figure><p>設定内容は以下のようにします</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c4c4f6dce6535e2b3d5e579fe9ce3e5c/href">https://medium.com/media/c4c4f6dce6535e2b3d5e579fe9ce3e5c/href</a></iframe><p>次に”+ Create Deployment”をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NIS1alx7ieVtTE3fq5-Fcw.png" /></figure><p>Deploymentの設定画面が開きます</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5r3Hu7vYFZf72qZTsMZkKw.png" /></figure><p>設定内容は以下のようにします</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4a6fb4845d0390e1d626d4d5f7874dcc/href">https://medium.com/media/4a6fb4845d0390e1d626d4d5f7874dcc/href</a></iframe><p>最後にHTTP Serviceを作成します。”+ Create HTTP Service”をクリックします</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AGsPMq7SVL_LkIS_ye8kkQ.png" /></figure><p>HTTP Serviceの設定画面が開きます</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7zuO2qo_xqKkabNbjeX0BQ.png" /></figure><p>設定内容は以下のようにします</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/930cddcb855fd5a0654bb165c0ccd294/href">https://medium.com/media/930cddcb855fd5a0654bb165c0ccd294/href</a></iframe><h4>推論させてみる</h4><p>“Check”をクリックすると、推論のテストをすることができます</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*B-LDvv6zCSSPhI7c51Neyg.png" /></figure><p>ここでは、筆者撮影の新幹線画像をアップロードして、推論させてみることにします</p><p><strong>E5系</strong></p><p>E5系である可能性(probability)がほぼ100%</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-s2oFhDQLngrNpMZBEHBAg.png" /></figure><p><strong>N700系</strong></p><p>N700系である可能性(probability)がほぼ100%</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cCyzf_FOTshSUNhN_01vbg.png" /></figure><p>正しく分類できているようです</p><h3>まとめ</h3><p>ABEJA Platformを使用して、E5系とN700系の画像を分類するモデルを学習・デプロイすることができました。データセット・学習ジョブ・推論エンドポイントをそれぞれ紐づけることができ、バージョン管理もできるのでサクサク進みました。今後例えば「E6系E7系や700系800系も追加したい」となった時に、データセットや学習用サーバが散乱せずに済みそうです</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=23620878ca55" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>