<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja-JP"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="/atom.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" hreflang="ja-JP" /><updated>2026-05-31T08:47:56+09:00</updated><id>/atom.xml</id><title type="html">tanapp</title><subtitle>目指せ、個人開発</subtitle><author><name>Tana Gone</name></author><entry><title type="html">Rapsberry Pi(Debian Linux 12)でCloudflare Warp(svc, cli)を使ってみる</title><link href="/ruby/cloudflare-warp/" rel="alternate" type="text/html" title="Rapsberry Pi(Debian Linux 12)でCloudflare Warp(svc, cli)を使ってみる" /><published>2026-04-23T14:14:47+09:00</published><updated>2026-04-23T14:14:47+09:00</updated><id>/ruby/cloudflare-warp</id><content type="html" xml:base="/ruby/cloudflare-warp/"><![CDATA[<p>Cloudflare WarpってのはCloudflare社のVPSをlocalhostのsocks5 Proxyに見せるためのdaemonとコマンドのセットである。</p>

<ol>
  <li>
    <p>apt-get install cloudflare-warpコマンド
コマンドの実行のためにはdeb PackageのURLを取得する必要がある。取得の方法はデベロッパーサイトに記載されてある。</p>

    <p><a href="https://developers.cloudflare.com/">Developers</a>
View all docs -&gt; Warp Client -&gt; OS clients -&gt; Linux</p>

    <p><a href="https://pkg.cloudflareclient.com/">Cloudflare WARP packages</a></p>
  </li>
  <li>
    <p>daemonが起動したことの確認とsocks5 Proxyの設定、動作確認</p>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% <span class="nb">sudo </span>systemctl status warp-svc.service
● warp-svc.service - Cloudflare Zero Trust Client Daemon
     Loaded: loaded <span class="o">(</span>/lib/systemd/system/warp-svc.service<span class="p">;</span> enabled<span class="p">;</span> preset: ena&gt;
     Active: active <span class="o">(</span>running<span class="o">)</span> since Wed 2026-04-22 10:16:25 JST<span class="p">;</span> 47s ago
   Main PID: 18151 <span class="o">(</span>warp-svc<span class="o">)</span>
      Tasks: 30 <span class="o">(</span>limit: 9259<span class="o">)</span>
        CPU: 209ms
     CGroup: /system.slice/warp-svc.service
             └─18151 /bin/warp-svc
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% warp-cli registration new
Success

% warp-cli connect
Success

% warp-cli status
Status update: Connected
Network: healthy

% warp-cli mode proxy
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% curl <span class="nt">-x</span> socks5h://127.0.0.1:40000 https://inet-ip.info/ip
104.28.xxx.xxx
</code></pre></div></div>

<ol>
  <li>
    <p>Proxyを複数作成する</p>

    <p>warp-dockerを複数起動すればProxyを複数作成できる。</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">--socks5-hostname</span> 127.0.0.1:1080 https://cloudflare.com/cdn-cgi/trace
</code></pre></div>    </div>

    <p><a href="https://github.com/cmj2002/warp-docker">cmj2002/warp-docker: Run Cloudflare WARP in Docker.</a></p>

    <p><a href="https://github.com/smol-machines">smol machines</a></p>
  </li>
</ol>]]></content><author><name>Tana Gone</name></author><category term="Ruby" /><summary type="html"><![CDATA[Cloudflare WarpってのはCloudflare社のVPSをlocalhostのsocks5 Proxyに見せるためのdaemonとコマンドのセットである。]]></summary></entry><entry><title type="html">Pythonでgif animationファイルを作る2つの方法</title><link href="/python/pythongif-animation/" rel="alternate" type="text/html" title="Pythonでgif animationファイルを作る2つの方法" /><published>2026-04-12T09:49:43+09:00</published><updated>2026-04-12T09:49:43+09:00</updated><id>/python/pythongif-animation</id><content type="html" xml:base="/python/pythongif-animation/"><![CDATA[<p>強化学習でCartPole問題やGrid World問題を解く際に学習の進捗を映像で知りたい。動画なら一目で進捗が解る。</p>

<h3 id="matplotlib付属のanimationとpillowpython-image-library-ish">matplotlib付属のanimationとpillow(python image library-ish)</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="n">gymnasium</span> <span class="k">as</span> <span class="n">gym</span>
<span class="kn">from</span> <span class="n">matplotlib</span> <span class="kn">import</span> <span class="n">animation</span>

<span class="k">def</span> <span class="nf">display_frames_as_gif</span><span class="p">(</span><span class="n">frames</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">
    Displays a list of frames as a gif
    </span><span class="sh">"""</span>
    <span class="n">plt</span><span class="p">.</span><span class="nf">figure</span><span class="p">(</span>
        <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="n">frames</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">/</span> <span class="mf">72.0</span><span class="p">,</span> <span class="n">frames</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">/</span> <span class="mf">72.0</span><span class="p">),</span>
        <span class="n">dpi</span><span class="o">=</span><span class="mi">72</span>
    <span class="p">)</span>
    <span class="n">patch</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="nf">imshow</span><span class="p">(</span><span class="n">frames</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">plt</span><span class="p">.</span><span class="nf">axis</span><span class="p">(</span><span class="sh">'</span><span class="s">off</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">animate</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
        <span class="n">patch</span><span class="p">.</span><span class="nf">set_data</span><span class="p">(</span><span class="n">frames</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
        <span class="k">return</span> <span class="n">patch</span><span class="p">,</span>

    <span class="n">anim</span> <span class="o">=</span> <span class="n">animation</span><span class="p">.</span><span class="nc">FuncAnimation</span><span class="p">(</span><span class="n">plt</span><span class="p">.</span><span class="nf">gcf</span><span class="p">(),</span> <span class="n">animate</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="nf">len</span><span class="p">(</span><span class="n">frames</span><span class="p">),</span>
        <span class="n">interval</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>

    <span class="n">anim</span><span class="p">.</span><span class="nf">save</span><span class="p">(</span><span class="sh">"</span><span class="s">movie_cartpole.gif</span><span class="sh">"</span><span class="p">,</span> <span class="n">writer</span><span class="o">=</span><span class="sh">"</span><span class="s">pillow</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">plt</span><span class="p">.</span><span class="nf">close</span><span class="p">()</span>

<span class="c1"># CartPole をランダムに動かす
</span><span class="n">frames</span> <span class="o">=</span> <span class="p">[]</span>

<span class="n">env</span> <span class="o">=</span> <span class="n">gym</span><span class="p">.</span><span class="nf">make</span><span class="p">(</span><span class="sh">"</span><span class="s">CartPole-v1</span><span class="sh">"</span><span class="p">,</span> <span class="n">render_mode</span><span class="o">=</span><span class="sh">"</span><span class="s">rgb_array</span><span class="sh">"</span><span class="p">)</span>
<span class="n">observation</span><span class="p">,</span> <span class="n">info</span> <span class="o">=</span> <span class="n">env</span><span class="p">.</span><span class="nf">reset</span><span class="p">()</span>

<span class="k">for</span> <span class="n">step</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">200</span><span class="p">):</span>
    <span class="n">frame</span> <span class="o">=</span> <span class="n">env</span><span class="p">.</span><span class="nf">render</span><span class="p">()</span>
    <span class="n">frames</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">frame</span><span class="p">)</span>

    <span class="n">action</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="nf">choice</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
    <span class="n">observation</span><span class="p">,</span> <span class="n">reward</span><span class="p">,</span> <span class="n">terminated</span><span class="p">,</span> <span class="n">truncated</span><span class="p">,</span> <span class="n">info</span> <span class="o">=</span> <span class="n">env</span><span class="p">.</span><span class="nf">step</span><span class="p">(</span><span class="n">action</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">terminated</span> <span class="ow">or</span> <span class="n">truncated</span><span class="p">:</span>
        <span class="k">break</span>

<span class="n">env</span><span class="p">.</span><span class="nf">close</span><span class="p">()</span>

<span class="c1"># 動画を保存
</span><span class="nf">display_frames_as_gif</span><span class="p">(</span><span class="n">frames</span><span class="p">)</span>
</code></pre></div></div>

<ol>
  <li>framesには複数枚の画像に相当する数値データが格納されている</li>
  <li>plt.figureでgifファイルの縦横の大きさがセットされる</li>
  <li>plt.imshowで1枚の画像に相当するpatchが作成</li>
  <li>patch.set_dataでpatchの中身が入れ替わる</li>
  <li>animation.Funcanimationへanimate callback関数を登録すると連続画像のオブジェクトが生成</li>
  <li>anim.saveでgif動画が保存される</li>
</ol>

<div align="center"><img src="/images/2026/movie_qlearning.gif" alt="movie_qlearning" style="zoom:33%;" /></div>

<h3 id="matplotlib付属のmatplotlibpyplotとpilpython-image-library">matplotlib付属のmatplotlib.pyplotとPIL(python image library)</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="n">io</span>
<span class="kn">from</span> <span class="n">PIL</span> <span class="kn">import</span> <span class="n">Image</span>

<span class="n">x_list</span> <span class="o">=</span> <span class="nf">range</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
<span class="n">y_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">x_val</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x_val</span> <span class="ow">in</span> <span class="n">x_list</span><span class="p">]</span>

<span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="nf">figure</span><span class="p">()</span>

<span class="n">img_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">x_val</span><span class="p">,</span> <span class="n">y_val</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">x_list</span><span class="p">,</span> <span class="n">y_list</span><span class="p">):</span>
    <span class="n">plt</span><span class="p">.</span><span class="nf">xlim</span><span class="p">(</span><span class="n">x_list</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x_list</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
    <span class="n">plt</span><span class="p">.</span><span class="nf">ylim</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">y_list</span><span class="p">),</span> <span class="nf">max</span><span class="p">(</span><span class="n">y_list</span><span class="p">))</span>
    <span class="n">plt</span><span class="p">.</span><span class="nf">scatter</span><span class="p">(</span><span class="n">x_val</span><span class="p">,</span> <span class="n">y_val</span><span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="sh">"</span><span class="s">tab:blue</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">img_bytes</span> <span class="o">=</span> <span class="n">io</span><span class="p">.</span><span class="nc">BytesIO</span><span class="p">()</span>
    <span class="n">plt</span><span class="p">.</span><span class="nf">savefig</span><span class="p">(</span><span class="n">img_bytes</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="sh">"</span><span class="s">png</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="n">img_bytes</span><span class="p">)</span>
    <span class="n">img_list</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
    
<span class="n">img_list</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">save</span><span class="p">(</span><span class="sh">"</span><span class="s">pillow_sample2.gif</span><span class="sh">"</span><span class="p">,</span> 
<span class="n">save_all</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">append_images</span><span class="o">=</span><span class="n">img_list</span><span class="p">[</span><span class="mi">1</span><span class="p">:],</span> <span class="n">optimize</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">duration</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">loop</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</code></pre></div></div>

<div align="center"><img src="images/2026/pillow_sample2.gif" alt="pillow_example" style="zoom:50%;" /></div>

<p><a href="https://3pysci.com/python-matplotlib-92/">【matplotlib】PIL（Pillow）とBytesIOを使ってGIFアニメーションを作成する方法 3PySci</a></p>]]></content><author><name>Tana Gone</name></author><category term="Python" /><summary type="html"><![CDATA[強化学習でCartPole問題やGrid World問題を解く際に学習の進捗を映像で知りたい。動画なら一目で進捗が解る。]]></summary></entry><entry><title type="html">tf.data使ってみる</title><link href="/python/tfdata/" rel="alternate" type="text/html" title="tf.data使ってみる" /><published>2026-04-12T04:38:54+09:00</published><updated>2026-04-12T04:38:54+09:00</updated><id>/python/tfdata</id><content type="html" xml:base="/python/tfdata/"><![CDATA[<p>TF1スタイルのコードを高速化するにはTF2(あるいはTF1.x最終版1.15)で採用された入力パイプラインを採用すれば良さそうだ</p>

<h3 id="tfdatadataset使ってみる">tf.data.Dataset使ってみる</h3>

<p>Denseへの入力が4、Weightsによって行列積Mによって変換された出力が1であるNNを訓練する。
訓練データがN個あればdatasetは次のようになる。
WはYの初期値を得るために乱数を使って作る。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> N <span class="o">=</span> 10<span class="p">;</span> D <span class="o">=</span> 4<span class="p">;</span> M <span class="o">=</span> 1
<span class="o">&gt;</span> X <span class="o">=</span> tf.random.normal<span class="o">((</span>N, D<span class="o">))</span>
<span class="o">&gt;</span> X
<span class="o">&gt;</span> &lt;tf.Tensor: <span class="nv">shape</span><span class="o">=(</span>10, 4<span class="o">)</span>, <span class="nv">dtype</span><span class="o">=</span>float32, <span class="nv">numpy</span><span class="o">=</span>
<span class="o">&gt;</span> array<span class="o">([[</span> 1.7476182 ,  0.76557606,  1.1793045 ,  0.6604082 <span class="o">]</span>,
<span class="o">&gt;</span>   <span class="o">[</span><span class="nt">-1</span>.1182905 ,  1.2941122 , <span class="nt">-0</span>.45307   , <span class="nt">-0</span>.12836482],
<span class="o">&gt;</span>   <span class="o">[</span> 1.3309119 ,  1.3667184 ,  2.4617343 , <span class="nt">-0</span>.44162795],
<span class="o">&gt;</span>   <span class="o">[</span> 0.09327319,  0.90526474,  0.6416567 , <span class="nt">-0</span>.17305161],
<span class="o">&gt;</span>   <span class="o">[</span><span class="nt">-1</span>.4737343 , <span class="nt">-2</span>.0090747 , <span class="nt">-0</span>.1392107 ,  0.32674456],
<span class="o">&gt;</span>   <span class="o">[</span> 0.25767186, <span class="nt">-0</span>.19082204, <span class="nt">-1</span>.9285886 , <span class="nt">-0</span>.47859055],
<span class="o">&gt;</span>   <span class="o">[</span><span class="nt">-0</span>.67001045,  0.02660223, <span class="nt">-0</span>.6753374 ,  0.04300369],
<span class="o">&gt;</span>   <span class="o">[</span><span class="nt">-0</span>.26570737,  1.748417  , <span class="nt">-0</span>.41708243, <span class="nt">-0</span>.4584445 <span class="o">]</span>,
<span class="o">&gt;</span>   <span class="o">[</span> 0.8148399 ,  0.22168487,  0.01016708, <span class="nt">-0</span>.8258183 <span class="o">]</span>,
<span class="o">&gt;</span>   <span class="o">[</span><span class="nt">-0</span>.34755087,  0.21631955,  0.36211625, <span class="nt">-1</span>.142048  <span class="o">]]</span>,
<span class="o">&gt;</span>  <span class="nv">dtype</span><span class="o">=</span>float32<span class="o">)&gt;</span>
<span class="o">&gt;</span> W <span class="o">=</span> tf.random.normal<span class="o">((</span>D, M<span class="o">))</span>
<span class="o">&gt;</span> Y <span class="o">=</span> tf.matmul<span class="o">(</span>X, W<span class="o">)</span>
<span class="o">&gt;</span> <span class="c"># ここまでが準備</span>
<span class="o">&gt;</span> <span class="c"># Batch Size = 3とするとBatch #1, 2, 3, 4が出来る。最後の#4はBatch Size = 1</span>
<span class="o">&gt;</span> ds_mini <span class="o">=</span> tf.data.Dataset.from_tensor_slices<span class="o">((</span>X, Y<span class="o">))</span>.shuffle<span class="o">(</span>N<span class="o">)</span>.batch<span class="o">(</span>3<span class="o">)</span><span class="se">\</span>
.prefetch<span class="o">(</span>tf.data.AUTOTUNE<span class="o">)</span>
<span class="o">&gt;</span> <span class="k">for </span>x_batch, y_batch <span class="k">in </span>ds_full:
<span class="o">&gt;</span> ...    print<span class="o">(</span>x_batch<span class="o">)</span>
<span class="o">&gt;</span> ...    print<span class="o">(</span>y_batch<span class="o">)</span>

tf.Tensor<span class="o">(</span>
<span class="o">[[</span> 0.25767186 <span class="nt">-0</span>.19082204 <span class="nt">-1</span>.9285886  <span class="nt">-0</span>.47859055]
 <span class="o">[</span> 0.09327319  0.90526474  0.6416567  <span class="nt">-0</span>.17305161]
 <span class="o">[</span> 0.8148399   0.22168487  0.01016708 <span class="nt">-0</span>.8258183 <span class="o">]]</span>, <span class="nv">shape</span><span class="o">=(</span>3, 4<span class="o">)</span>, <span class="nv">dtype</span><span class="o">=</span>float32<span class="o">)</span>
tf.Tensor<span class="o">(</span>
<span class="o">[[</span> 0.3514151 <span class="o">]</span>
 <span class="o">[</span><span class="nt">-0</span>.2899059 <span class="o">]</span>
 <span class="o">[</span> 0.49854147]], <span class="nv">shape</span><span class="o">=(</span>3, 1<span class="o">)</span>, <span class="nv">dtype</span><span class="o">=</span>float32<span class="o">)</span>
 ...以下略
</code></pre></div></div>
<h3 id="nnlearnds_mini">nn.learn(ds_mini)</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> model <span class="o">=</span> tf.keras.Sequential<span class="o">([</span>
<span class="o">&gt;</span> ...  tf.keras.layers.Flatten<span class="o">()</span>,
<span class="o">&gt;</span> ...  tf.keras.layers.Dense<span class="o">(</span>10<span class="o">)</span>
<span class="o">&gt;</span> ...]<span class="o">)</span>
<span class="o">&gt;</span> model.compile<span class="o">(</span><span class="nv">optimizer</span><span class="o">=</span><span class="s1">'adam'</span>,
<span class="o">&gt;</span> ... <span class="nv">loss</span><span class="o">=</span><span class="s1">'mean_squared_error'</span>,
<span class="o">&gt;</span> ... <span class="nv">metrics</span><span class="o">=[</span><span class="s1">'mse'</span><span class="o">])</span>
<span class="o">&gt;</span> model.fit<span class="o">(</span>ds_mini, <span class="nv">epochs</span><span class="o">=</span>1<span class="o">)</span>
<span class="o">&gt;</span> 4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - loss: 2.2483 - mse: 2.2483
<span class="o">&gt;</span> &lt;keras.src.callbacks.history.History object at 0x11e6c0e10&gt;
<span class="o">&gt;</span> model.fit<span class="o">(</span>ds_mini, <span class="nv">epochs</span><span class="o">=</span>2<span class="o">)</span>
<span class="o">&gt;</span> Epoch 1/2
<span class="o">&gt;</span> 4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 749us/step - loss: 2.2319 - mse: 2.2319
<span class="o">&gt;</span> Epoch 2/2
<span class="o">&gt;</span> 4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 640us/step - loss: 2.2156 - mse: 2.2156
<span class="o">&gt;</span> &lt;keras.src.callbacks.history.History object at 0x11e688050&gt;
</code></pre></div></div>

<h3 id="入力パイプラインはcpuとgpuを交互動作ではなく同時動作させる">入力パイプラインはCPUとGPUを交互動作ではなく同時動作させる</h3>

<p>TF1のコードスタイルですか？それともTF2ですか？それともTF1, TF2共通のコードスタイルですか？</p>

<p><a href="https://www.tensorflow.org/guide/data?hl=ja#tfkeras_%E3%81%A8_tfdata_%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B">tf.data: TensorFlow 入力パイプラインの構築  TensorFlow Core</a></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">train</span><span class="p">,</span> <span class="n">test</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">datasets</span><span class="p">.</span><span class="n">fashion_mnist</span><span class="p">.</span><span class="nf">load_data</span><span class="p">()</span>

<span class="n">images</span><span class="p">,</span> <span class="n">labels</span> <span class="o">=</span> <span class="n">train</span>
<span class="n">images</span> <span class="o">=</span> <span class="n">images</span><span class="o">/</span><span class="mf">255.0</span>
<span class="n">labels</span> <span class="o">=</span> <span class="n">labels</span><span class="p">.</span><span class="nf">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">int32</span><span class="p">)</span>
<span class="n">fmnist_train_ds</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">Dataset</span><span class="p">.</span><span class="nf">from_tensor_slices</span><span class="p">((</span><span class="n">images</span><span class="p">,</span> <span class="n">labels</span><span class="p">))</span>
<span class="n">fmnist_train_ds</span> <span class="o">=</span> <span class="n">fmnist_train_ds</span><span class="p">.</span><span class="nf">shuffle</span><span class="p">(</span><span class="mi">5000</span><span class="p">).</span><span class="nf">batch</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="nc">Sequential</span><span class="p">([</span>
  <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="nc">Flatten</span><span class="p">(),</span>
  <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="nc">Dense</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
<span class="p">])</span>

<span class="n">model</span><span class="p">.</span><span class="nf">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="sh">'</span><span class="s">adam</span><span class="sh">'</span><span class="p">,</span>
  <span class="n">loss</span><span class="o">=</span><span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">losses</span><span class="p">.</span><span class="nc">SparseCategoricalCrossentropy</span><span class="p">(</span><span class="n">from_logits</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> 
  <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="sh">'</span><span class="s">accuracy</span><span class="sh">'</span><span class="p">])</span>

<span class="n">model</span><span class="p">.</span><span class="nf">fit</span><span class="p">(</span><span class="n">fmnist_train_ds</span><span class="p">,</span> <span class="n">epochs</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</code></pre></div></div>
<p>理由（主なポイント）</p>
<ul>
  <li>tf.keras.datasets.fashion_mnist.load_data() でデータを読み込んでいる → TF2の標準的なKeras API。</li>
  <li>tf.data.Dataset.from_tensor_slices() + .shuffle() + .batch() でデータパイプラインを作成している → TF2で強く推奨される効率的な入力パイプライン（TF1ではほとんど使われず、TF2以降の本流）。</li>
  <li>tf.keras.Sequential([…]) でモデル定義。</li>
  <li>model.compile() + model.fit(dataset, epochs=…) で訓練 → これがTF2の標準的な高レベルトレーニングAPI（eager execution前提）。</li>
</ul>

<p>TF1時代は以下のような違いがありました：</p>

<ul>
  <li>tf.Session() や tf.placeholder を明示的に使う</li>
  <li>tf.estimator や低レベルAPI（tf.train など）が主流</li>
  <li>Kerasは tf.keras として一部使えましたが、データ入力はNumPyを直接渡すことが多かった</li>
  <li>model.fit() に tf.data.Dataset を渡すスタイルはTF2で本格的に整備・推奨された</li>
</ul>

<h3 id="tf1スタイル">TF1スタイル</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># TF1で動くように修正した例
</span><span class="kn">import</span> <span class="n">tensorflow</span> <span class="k">as</span> <span class="n">tf</span>
<span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="p">(</span><span class="n">train_images</span><span class="p">,</span> <span class="n">train_labels</span><span class="p">),</span> <span class="n">_</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">datasets</span><span class="p">.</span><span class="n">fashion_mnist</span><span class="p">.</span><span class="nf">load_data</span><span class="p">()</span>

<span class="n">train_images</span> <span class="o">=</span> <span class="n">train_images</span> <span class="o">/</span> <span class="mf">255.0</span>
<span class="n">train_labels</span> <span class="o">=</span> <span class="n">train_labels</span><span class="p">.</span><span class="nf">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">int32</span><span class="p">)</span>

<span class="c1"># tf.data を使わず、NumPy配列を直接渡す（TF1で最も安定）
</span><span class="n">model</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="nc">Sequential</span><span class="p">([</span>
    <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="nc">Flatten</span><span class="p">(),</span>
    <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="nc">Dense</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
<span class="p">])</span>

<span class="n">model</span><span class="p">.</span><span class="nf">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="sh">'</span><span class="s">adam</span><span class="sh">'</span><span class="p">,</span>
              <span class="n">loss</span><span class="o">=</span><span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">losses</span><span class="p">.</span><span class="nc">SparseCategoricalCrossentropy</span><span class="p">(</span><span class="n">from_logits</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span>
              <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="sh">'</span><span class="s">accuracy</span><span class="sh">'</span><span class="p">])</span>

<span class="n">model</span><span class="p">.</span><span class="nf">fit</span><span class="p">(</span><span class="n">train_images</span><span class="p">,</span> <span class="n">train_labels</span><span class="p">,</span> <span class="n">epochs</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">32</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="どちらが高速">どちらが高速？</h3>

<ol>
  <li>入力パイプラインの違いによる速度比較</li>
</ol>

<ul>
  <li>TF1スタイル（NumPy配列を直接 model.fit(x, y) に渡す）
    <ul>
      <li>メリット：コードがシンプル。データがメモリにすべて載る小規模データセットではオーバーヘッドが少ない。</li>
      <li>デメリット：毎エポックでTensorFlowが内部的にデータをコピーしたり、GPUへの転送が非効率になりやすい。特にGPU使用時や複数エポックで入力がボトルネックになる。</li>
    </ul>
  </li>
  <li>TF2スタイル（tf.data.Dataset + shuffle + batch）
    <ul>
      <li>メリット：TensorFlow公式が強く推奨する理由があり、入力パイプラインが大幅に最適化される。
        <ul>
          <li>非同期データ読み込み（prefetch）</li>
          <li>効率的なバッチ処理とシャッフル</li>
          <li>GPU/CPU間のデータ転送が最適化されやすい</li>
        </ul>
      </li>
      <li>特にGPUを使っている場合や、エポック数が多いときに入力待ち時間が減り、GPU利用率が向上して全体のトレーニングが速くなる。</li>
    </ul>
  </li>
</ul>

<ol>
  <li>実行モードの影響（TF2特有）TF2のmodel.fit()はデフォルトでeager executionですが、内部的にグラフ最適化（tf.function相当）も一部使っています。</li>
</ol>

<ul>
  <li>純粋なTF1（静的グラフ + Session）は、シンプルなモデルではまだ高速な場合があります（特に古いベンチマークではTF1が勝つ例あり）。</li>
  <li>しかし、現代のTF2.10以降では、tf.data + tf.functionの組み合わせがTF1時代の静的グラフを上回るか同等以上の性能を出せるよう最適化が進んでいます。</li>
</ul>]]></content><author><name>Tana Gone</name></author><category term="Python" /><summary type="html"><![CDATA[TF1スタイルのコードを高速化するにはTF2(あるいはTF1.x最終版1.15)で採用された入力パイプラインを採用すれば良さそうだ]]></summary></entry><entry><title type="html">Python環境にtensorflow-metalをインストール</title><link href="/python/pythontensorflow-metal/" rel="alternate" type="text/html" title="Python環境にtensorflow-metalをインストール" /><published>2026-03-09T21:47:34+09:00</published><updated>2026-03-09T21:47:34+09:00</updated><id>/python/pythontensorflow-metal</id><content type="html" xml:base="/python/pythontensorflow-metal/"><![CDATA[<p>強化学習の本に掲載されているサンプルコードを動かしてみるとDQNのコードの実行に2hr17minも要してしまう。Macbook ProのGPUを活用して実行の短縮を計ることを試みてみた。</p>

<p><a href="https://info.nikkeibp.co.jp/media/NSW/atcl/books/111100051/">「強化学習」を学びたい人が最初に読む本 日経ソフトウエア</a>
<br />
日経ソフトウエア2021-07に連載開始され、2021-11に出版された本
<br />
<a href="https://itoshi.main.jp/tech/2021/10/27/book_irl/">書籍「強化学習を学びたい人が最初に読む本」が出版されます M-note　プログラムと電子工作</a>
<br />
著者のブログ
<br />
<a href="https://github.com/itoshin-tech/memoryRL">itoshin-tech/memoryRL</a>
<br />
ブログの強化学習連載で解説されているソース</p>

<div align="center"><img src="/images/2026/netQ_random.gif" alt="netQrandom" style="zoom:33%;" /></div>

<h3 id="tensorflow-metalインストールに失敗">tensorflow-metalインストールに失敗</h3>

<p>tensorflow-metalをpipでインストールしようとしてもpythonのversionが新しすぎて失敗する。</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$python</span> <span class="nt">--version</span>
Python 3.13.2
<span class="nv">$mkdir</span> foo<span class="p">;</span><span class="nb">cd </span>foo
<span class="nv">$python</span> <span class="nt">-m</span> venv <span class="nb">.</span>
<span class="nv">$source</span> bin/activate
<span class="o">(</span>foo<span class="o">)</span><span class="nv">$pip</span> <span class="nb">install </span>tensorflow-metal
ERROR: Could not find a version that satisfies the requirement tensorflow-metal <span class="o">(</span>from versions: none<span class="o">)</span>
</code></pre></div></div>

<h3 id="uvを使ってみる">uvを使ってみる</h3>

<p>venvとは別のPackage管理ツールuvを使ってみる。こいつはPackageだけでなくPythonのVersionも管理できる。uv officialからinstall.shを入手してgeminiに読んでもらった。するとscriptのusageにインストール先が記載されている。zprofileやzshrcを書き換えて、恒久的なPATH変更は行わずsource ~/.local/bin/envすればuvバイナリにPATHが通る。</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$sh</span> install.sh
<span class="nv">$source</span> ~/.local/bin/env
<span class="nv">$uv</span> python <span class="nb">install </span>3.10 <span class="c"># or uv python pin 3.10, if already installed.</span>
<span class="nv">$mkdir</span> metal<span class="p">;</span> <span class="nb">cd </span>metal
<span class="nv">$uv</span> init <span class="nb">.</span>
<span class="nv">$uv</span> add tensorflow-metal
<span class="nv">$uv</span> add <span class="nv">tensorflow</span><span class="o">==</span>2.19
<span class="nv">$uv</span> run python
<span class="o">&gt;&gt;&gt;</span> import tensorflow as tf
<span class="o">&gt;&gt;&gt;</span> tf.config.list_physical_devices<span class="o">(</span><span class="s1">'GPU'</span><span class="o">)</span> <span class="c"># device_type文字列を与えると配列が返る</span>
<span class="o">[</span>PhysicalDevice<span class="o">(</span><span class="nv">name</span><span class="o">=</span><span class="s1">'/physical_device:GPU:0'</span>, <span class="nv">device_type</span><span class="o">=</span><span class="s1">'GPU'</span><span class="o">)]</span>
<span class="o">&gt;&gt;&gt;</span> tf.config.list_physical_devices<span class="o">(</span><span class="s1">'TPU'</span><span class="o">)</span>
<span class="o">[]</span>
</code></pre></div></div>

<p>Python 3.9以降でないとtensorflow-metalはインストール出来ない。tensorflowは最新版2.21ではNGだったので2.19をチョイス。</p>

<p>インストールには成功している様だ。</p>

<p><a href="https://developer.apple.com/metal/tensorflow-plugin/">Tensorflow Plugin - Metal - Apple Developer</a></p>

<p><a href="https://github.com/astral-sh/uv">astral-sh/uv: An extremely fast Python package and project manager, written in Rust.</a></p>

<p><a href="https://qiita.com/GeneLab_999/items/29d24899fcc61a2ca801">uv とは何か？その設計思想と再現性ある環境構築のためのガイド #Rust - Qiita</a></p>

<p><a href="https://mac.install.guide/python/install-uv">Install Python with UV · Mac Install Guide · 2026</a></p>

<h3 id="使ってみる">使ってみる</h3>

<p>次のコード(memory usage 7.2GB, CPU Time 30min)でGPUが使われるのかを検証してみる</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">tensorflow</span> <span class="k">as</span> <span class="n">tf</span>

<span class="n">cifar</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">datasets</span><span class="p">.</span><span class="n">cifar100</span>
<span class="p">(</span><span class="n">x_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">),</span> <span class="p">(</span><span class="n">x_test</span><span class="p">,</span> <span class="n">y_test</span><span class="p">)</span> <span class="o">=</span> <span class="n">cifar</span><span class="p">.</span><span class="nf">load_data</span><span class="p">()</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">applications</span><span class="p">.</span><span class="nc">ResNet50</span><span class="p">(</span>
    <span class="n">include_top</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
    <span class="n">weights</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
    <span class="n">input_shape</span><span class="o">=</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span>
    <span class="n">classes</span><span class="o">=</span><span class="mi">100</span><span class="p">,)</span>

<span class="n">loss_fn</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">losses</span><span class="p">.</span><span class="nc">SparseCategoricalCrossentropy</span><span class="p">(</span><span class="n">from_logits</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">model</span><span class="p">.</span><span class="nf">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="sh">"</span><span class="s">adam</span><span class="sh">"</span><span class="p">,</span> <span class="n">loss</span><span class="o">=</span><span class="n">loss_fn</span><span class="p">,</span> <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="sh">"</span><span class="s">accuracy</span><span class="sh">"</span><span class="p">])</span>
<span class="n">model</span><span class="p">.</span><span class="nf">fit</span><span class="p">(</span><span class="n">x_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span> <span class="n">epochs</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">64</span><span class="p">)</span>
</code></pre></div></div>

<p>アクティビティ・モニタからはGPUが使用されていることが見て取れる</p>

<div align="center"><img src="/images/2026/resNet50.png" alt="resNet50" style="zoom:33%;" /></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$uv</span> run python chk_metal.py
2026-03-09 21:01:43.181899: I metal_plugin/src/device/metal_device.cc:1154] Metal device <span class="nb">set </span>to: Apple M1 Pro
2026-03-09 21:01:43.182098: I metal_plugin/src/device/metal_device.cc:296] systemMemory: 16.00 GB
2026-03-09 21:01:43.182106: I metal_plugin/src/device/metal_device.cc:313] maxCacheSize: 5.92 GB
WARNING: All log messages before absl::InitializeLog<span class="o">()</span> is called are written to STDERR
I0000 00:00:1773057703.182527 79553837 pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support.
I0000 00:00:1773057703.182920 79553837 pluggable_device_factory.cc:271] Created TensorFlow device <span class="o">(</span>/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory<span class="o">)</span> -&gt; physical PluggableDevice <span class="o">(</span>device: 0, name: METAL, pci bus <span class="nb">id</span>: &lt;undefined&gt;<span class="o">)</span>
Epoch 1/5
2026-03-09 21:01:49.654876: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:117] Plugin optimizer <span class="k">for </span>device_type GPU is enabled.
782/782 ━━━━━━━━━━━━━━━━━━━━ 380s 439ms/step - accuracy: 0.0773 - loss: 4.7684
<span class="o">(</span>to be ommited<span class="o">)</span>
</code></pre></div></div>

<p>上記コードをepoch=2としてGPU使用の効果を確認してみる
<br />無し: uv run python resNet50.py  2153.51s user 233.24s system 352% cpu 11:17.82 total
<br />有り: uv run python resNet50.py  599.40s user 271.22s system 147% cpu 9:50.82 total
<br />実行時間は87%にしかならん。GPU(M1 Pro)の能力が低いからか？</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$sw_vers</span>
ProductName:            macOS
ProductVersion:         26.2
BuildVersion:           25C56
</code></pre></div></div>

<h3 id="gpuの使用のonoff">GPUの使用のOn/Off</h3>

<p>ソースコードの改変が必要だ。環境変数による制御は効かない。</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">TF_DISABLE_METAL</span><span class="o">=</span>1          <span class="c"># 最近のtensorflow-metalで有効な場合あり</span>
<span class="c"># またはもっと強力に</span>
<span class="nb">export </span><span class="nv">CUDA_VISIBLE_DEVICES</span><span class="o">=</span><span class="s2">""</span>     <span class="c"># Metalでも一部効くケースがある（互換性のため）</span>
python your_script.py
</code></pre></div></div>

<p>次のコードの断片ではGPU Offとはならない</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">tensorflow</span> <span class="k">as</span> <span class="n">tf</span>
<span class="n">tf</span><span class="p">.</span><span class="n">debugging</span><span class="p">.</span><span class="nf">set_log_device_placement</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
<span class="c1"># Create some tensors
</span><span class="k">with</span> <span class="n">tf</span><span class="p">.</span><span class="nf">device</span><span class="p">(</span><span class="sh">'</span><span class="s">/CPU:0</span><span class="sh">'</span><span class="p">):</span>
  <span class="n">a</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="nf">constant</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">4.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">]])</span>
  <span class="n">b</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="nf">constant</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">5.0</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">]])</span>

<span class="n">c</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="nf">matmul</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2026-03-09 13:14:44.256613: I tensorflow/core/common_runtime/eager/execute.cc:1754] Executing op MatMul <span class="k">in </span>device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor<span class="o">(</span>
<span class="o">[[</span>22. 28.]
 <span class="o">[</span>49. 64.]], <span class="nv">shape</span><span class="o">=(</span>2, 2<span class="o">)</span>, <span class="nv">dtype</span><span class="o">=</span>float32<span class="o">)</span>
</code></pre></div></div>

<p>次のコードはGPU Offとなる例である(courtesy of Grok)</p>

<p><a href="https://www.tensorflow.org/api_docs/python/tf/config">Module: tf.config TensorFlow v2.16.1</a></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">tensorflow</span> <span class="k">as</span> <span class="n">tf</span>

<span class="c1"># これを最初（他のtf操作より前）に実行
</span><span class="n">tf</span><span class="p">.</span><span class="n">config</span><span class="p">.</span><span class="nf">set_visible_devices</span><span class="p">([],</span> <span class="sh">'</span><span class="s">GPU</span><span class="sh">'</span><span class="p">)</span>

<span class="c1"># 確認用（GPUが消えているはず）
</span><span class="nf">print</span><span class="p">(</span><span class="n">tf</span><span class="p">.</span><span class="n">config</span><span class="p">.</span><span class="nf">list_physical_devices</span><span class="p">())</span>          <span class="c1"># GPUが[]になる
</span><span class="nf">print</span><span class="p">(</span><span class="n">tf</span><span class="p">.</span><span class="n">config</span><span class="p">.</span><span class="nf">list_physical_devices</span><span class="p">(</span><span class="sh">'</span><span class="s">GPU</span><span class="sh">'</span><span class="p">))</span>     <span class="c1"># []
</span>
<span class="n">tf</span><span class="p">.</span><span class="n">debugging</span><span class="p">.</span><span class="nf">set_log_device_placement</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>

<span class="c1"># 以降のコード
</span><span class="n">a</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="nf">constant</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">4.0</span><span class="p">,</span> <span class="mf">5.0</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">]])</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="nf">constant</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">],</span> <span class="p">[</span><span class="mf">5.0</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">]])</span>

<span class="n">c</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="nf">matmul</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2026-03-09 13:33:55.970195: I tensorflow/core/common_runtime/eager/execute.cc:1754] Executing op MatMul <span class="k">in </span>device /job:localhost/replica:0/task:0/device:CPU:0
tf.Tensor<span class="o">(</span>
<span class="o">[[</span>22. 28.]
 <span class="o">[</span>49. 64.]], <span class="nv">shape</span><span class="o">=(</span>2, 2<span class="o">)</span>, <span class="nv">dtype</span><span class="o">=</span>float32<span class="o">)</span>
</code></pre></div></div>

<h3 id="gpuを活用したpythonコード">GPUを活用したPythonコード</h3>

<p><a href="https://qiita.com/ntaka329/items/ff4e0d266a46d7450664">Apple M4 MacでTensorFlowが爆速！GPU有効化etcで機械学習が10倍速くなる方法を解説 #AI - Qiita</a></p>]]></content><author><name>Tana Gone</name></author><category term="Python" /><summary type="html"><![CDATA[強化学習の本に掲載されているサンプルコードを動かしてみるとDQNのコードの実行に2hr17minも要してしまう。Macbook ProのGPUを活用して実行の短縮を計ることを試みてみた。]]></summary></entry><entry><title type="html">NavigationStackの使い方</title><link href="/swiftui/navigationstack/" rel="alternate" type="text/html" title="NavigationStackの使い方" /><published>2026-02-17T13:48:41+09:00</published><updated>2026-02-17T13:48:41+09:00</updated><id>/swiftui/navigationstack</id><content type="html" xml:base="/swiftui/navigationstack/"><![CDATA[<p>コンテナViewの再描画を誘発させるには状態変数@Stateの値を変える。コンテナViewとはNavigationStack, TabView, NavigationSplitView, LazyVGrid…などである。コンテナView単独ではViewを構成出来ず、単純View、基本Viewとでも言えるコンテナViewではないViewをコンテナViewへ格納することでViewを構成する。</p>

<p><a href="https://qiita.com/toasha/items/31b2c141831b90f7d11b#lazyvgrid--lazyhgrid">自分用にコンテナの種類をまとめる #初心者 - Qiita</a></p>

<p>状態変数@Stateの値を変えるにはコンテナViewではないView、例えばButton, Toggle, TextField, Picker, Stepper, Slider…がある。(Swiftポケットリファレンス第三版 Chapter6 2024)</p>

<p>コンテナViewではないViewにはコンテンツを表示するText, Image, Shape, List, Table…がある。Viewの全リストはXcodeを起動しDeveloper Documentationを開きView Protocolを検索すれば取得できる。検索結果の下の方のConforming Typesにアルファベット順に記載されている。この中にはDisclosureGroupの様な珍しいViewも現れる。</p>

<p>ここではNavigationStackの再描画、つまり画面遷移を状態変数pathを使って行う例を示す。コンテナViewの中にはToggleとButtonが入っている。空のpathコレクションに値が投入されると画面再描画が発生し画面遷移が起こる。戻るButtonが押下されるとpathコレクションの中身はpopされ空の状態に戻る。</p>

<p>遷移先はnavigationDestinationモディファイアで指定する。closureにはpathに投入された値がセットされる。navigationDestinationモディファイアには、セットされる値の型までは知らされない。型情報も同時に引数に与えて教える必要がある。</p>

<div align="center"><img src="/images/2026/navStack.gif" alt="navStack" style="zoom:33%;" /></div>

<p>遷移先として指定されているVStackに付与されているframeモディファイアはTextに付与しても良い。</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">ContentView</span><span class="p">:</span> <span class="kt">View</span> <span class="p">{</span>
  <span class="kd">@State</span> <span class="k">var</span> <span class="nv">path</span><span class="p">:</span> <span class="kt">NavigationPath</span> <span class="o">=</span> <span class="kt">NavigationPath</span><span class="p">()</span>
  <span class="kd">@State</span> <span class="k">var</span> <span class="nv">vibrateOnRing</span> <span class="p">:</span> <span class="kt">Bool</span> <span class="o">=</span> <span class="kc">false</span>

  <span class="k">var</span> <span class="nv">body</span><span class="p">:</span> <span class="kd">some</span> <span class="kt">View</span><span class="p">{</span>
    <span class="kt">NavigationStack</span><span class="p">(</span><span class="nv">path</span><span class="p">:</span> <span class="n">$path</span><span class="p">){</span>
        <span class="kt">Toggle</span><span class="p">(</span>
          <span class="s">"Vibrate on Ring"</span><span class="p">,</span>
          <span class="nv">systemImage</span><span class="p">:</span> <span class="s">"dot.radiowaves.left.and.right"</span><span class="p">,</span>
          <span class="nv">isOn</span><span class="p">:</span> <span class="n">$vibrateOnRing</span>
        <span class="p">)</span><span class="o">.</span><span class="nf">toggleStyle</span><span class="p">(</span><span class="o">.</span><span class="k">switch</span><span class="p">)</span>
          <span class="o">.</span><span class="nf">onChange</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="n">vibrateOnRing</span><span class="p">)</span> <span class="p">{</span> <span class="n">_</span><span class="p">,</span> <span class="n">newValue</span> <span class="k">in</span>
            <span class="n">path</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
          <span class="p">}</span>
        <span class="kt">Button</span><span class="p">(</span><span class="s">"遷移する"</span><span class="p">){</span>
            <span class="n">path</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="c1">//          withAnimation { path.append(0) }</span>
        <span class="p">}</span>
      <span class="o">.</span><span class="nf">navigationTitle</span><span class="p">(</span><span class="s">"ホーム"</span><span class="p">)</span>
      <span class="o">.</span><span class="nf">navigationDestination</span><span class="p">(</span><span class="nv">for</span><span class="p">:</span> <span class="kt">Int</span><span class="o">.</span><span class="k">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">e</span> <span class="k">in</span>
        <span class="kt">VStack</span> <span class="p">{</span>
<span class="c1">//          Color.clear // 背景を広げるために入れても良い</span>
          <span class="kt">Text</span><span class="p">(</span><span class="s">"hoge</span><span class="se">\(</span><span class="n">e</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
        <span class="p">}</span>
        <span class="o">.</span><span class="nf">frame</span><span class="p">(</span><span class="nv">maxWidth</span><span class="p">:</span> <span class="o">.</span><span class="n">infinity</span><span class="p">,</span> <span class="nv">maxHeight</span><span class="p">:</span> <span class="o">.</span><span class="n">infinity</span><span class="p">,</span> <span class="nv">alignment</span><span class="p">:</span> <span class="o">.</span><span class="n">center</span><span class="p">)</span>
      <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://qiita.com/yoshi-eng/items/91666637cd7cdd8edf88">NavigationStackを一番活かす人（SwiftUI） #iOS - Qiita</a></p>]]></content><author><name>Tana Gone</name></author><category term="SwiftUI" /><summary type="html"><![CDATA[コンテナViewの再描画を誘発させるには状態変数@Stateの値を変える。コンテナViewとはNavigationStack, TabView, NavigationSplitView, LazyVGrid…などである。コンテナView単独ではViewを構成出来ず、単純View、基本Viewとでも言えるコンテナViewではないViewをコンテナViewへ格納することでViewを構成する。]]></summary></entry><entry><title type="html">Listで配列の中身を弄くりたい</title><link href="/swiftui/array-with-list/" rel="alternate" type="text/html" title="Listで配列の中身を弄くりたい" /><published>2026-02-05T21:44:33+09:00</published><updated>2026-02-05T21:44:33+09:00</updated><id>/swiftui/array-with-list</id><content type="html" xml:base="/swiftui/array-with-list/"><![CDATA[<p>Drag’N’Dropで配列に要素を追加したり、要素を削除したり、要素の順番を変える方法を探る。以下のコードではalart Dialogの出し方も記載されている。</p>

<p><a href="https://software.small-desk.com/development/2024/09/10/swiftui-howto-draganddropt-table/">SwiftUI TableでRowをDrag&amp;Dropする SmallDeskSoftware</a></p>

<p><a href="https://capibara1969.com/1443/">【SwiftUI】Listの行削除 カピ通信</a></p>

<div align="center"><img align="center" src="/images/2026/ArArange.gif" alt="ArArange" style="zoom:33%;" /></div>

<h3 id="コード解説">コード解説</h3>

<p>要素の移動、削除の際に呼び出されるonMove, onDeleteに引数で渡ってくる値、引数に渡さないといけない値は全く異なる。同じにしておいてくれれば良いのだが。onDeleteでは削除後にCallbackされるメソッドを引数に与える。メソッドにセットされる引数はListのIndex番号(IndexSet型)だ。onDeleteはListのCellを2本指Swipeすれば呼び出せるのだが、ContextMenuを使う方が簡単だ。ContextMenuはListにセットするのではなくListに表示されるCellにセットする。</p>

<p>要素の追加にはalart Dialogを使うのだが、ListにセットしてもListを格納したVStackにセットしても機能するようだ。alart Dialog表示/非表示の制御にはView状態管理変数＠State変数を使えば良い。alart Dialogで受け取ったItem構造体のメンバー(タイトル、値)がViewに伝わる様にView状態管理変数@Stateが同じく使われる。</p>

<p>追加によって要素がWindow Sizeを超えて表示されない場合でもScroll Barが自動で付加されるのが嬉しい。</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">SwiftUI</span>

<span class="kd">struct</span> <span class="kt">Item</span><span class="p">:</span> <span class="kt">Identifiable</span><span class="p">,</span> <span class="kt">Equatable</span> <span class="p">{</span>
  <span class="k">let</span> <span class="nv">id</span> <span class="o">=</span> <span class="kt">UUID</span><span class="p">()</span>
  <span class="k">let</span> <span class="nv">title</span><span class="p">:</span><span class="kt">String</span>
  <span class="k">let</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">Int</span>
<span class="p">}</span>

<span class="kd">struct</span> <span class="kt">ContentView</span><span class="p">:</span> <span class="kt">View</span> <span class="p">{</span>
  <span class="kd">@State</span> <span class="k">var</span> <span class="nv">listItems</span> <span class="o">=</span> <span class="p">[</span><span class="kt">Item</span><span class="p">(</span><span class="nv">title</span><span class="p">:</span> <span class="s">"Item1"</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="mi">9</span><span class="p">),</span> <span class="kt">Item</span><span class="p">(</span><span class="nv">title</span><span class="p">:</span> <span class="s">"Item2"</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="mi">12</span><span class="p">),</span> <span class="kt">Item</span><span class="p">(</span><span class="nv">title</span><span class="p">:</span> <span class="s">"Item3"</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="mi">15</span><span class="p">)]</span>
  <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">showingAddDialog</span> <span class="o">=</span> <span class="kc">false</span>
  <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">newTitle</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">""</span>
  <span class="kd">@State</span> <span class="kd">private</span> <span class="k">var</span> <span class="nv">newValueText</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">""</span>

  <span class="k">var</span> <span class="nv">body</span><span class="p">:</span> <span class="kd">some</span> <span class="kt">View</span> <span class="p">{</span>
    <span class="kt">VStack</span> <span class="p">{</span>
      <span class="kt">List</span> <span class="p">{</span>
        <span class="kt">ForEach</span><span class="p">(</span><span class="n">listItems</span><span class="p">,</span> <span class="nv">id</span><span class="p">:</span> <span class="p">\</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="p">{</span> <span class="n">item</span> <span class="k">in</span>
          <span class="kt">HStack</span> <span class="p">{</span>
            <span class="kt">Text</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">title</span><span class="p">)</span>
            <span class="kt">Text</span><span class="p">(</span><span class="s">"</span><span class="se">\(</span><span class="n">item</span><span class="o">.</span><span class="n">value</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
          <span class="p">}</span>
          <span class="o">.</span><span class="nf">frame</span><span class="p">(</span><span class="nv">height</span><span class="p">:</span> <span class="mi">30</span><span class="p">)</span>
          <span class="o">.</span><span class="n">contextMenu</span> <span class="p">{</span>
            <span class="kt">Button</span><span class="p">(</span><span class="nv">role</span><span class="p">:</span> <span class="o">.</span><span class="n">destructive</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">if</span> <span class="k">let</span> <span class="nv">index</span> <span class="o">=</span> <span class="n">listItems</span><span class="o">.</span><span class="nf">firstIndex</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="n">item</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">listItems</span><span class="o">.</span><span class="nf">remove</span><span class="p">(</span><span class="nv">at</span><span class="p">:</span> <span class="n">index</span><span class="p">)</span>
              <span class="p">}</span>
            <span class="p">}</span> <span class="nv">label</span><span class="p">:</span> <span class="p">{</span>
              <span class="kt">Label</span><span class="p">(</span><span class="s">"Delete"</span><span class="p">,</span> <span class="nv">systemImage</span><span class="p">:</span> <span class="s">"trash"</span><span class="p">)</span>
            <span class="p">}</span>
          <span class="p">}</span>
        <span class="p">}</span>
        <span class="o">.</span><span class="n">onMove</span> <span class="p">{</span> <span class="n">indexSet</span><span class="p">,</span> <span class="n">dest</span> <span class="k">in</span>
          <span class="n">listItems</span><span class="o">.</span><span class="nf">move</span><span class="p">(</span><span class="nv">fromOffsets</span><span class="p">:</span> <span class="n">indexSet</span><span class="p">,</span> <span class="nv">toOffset</span><span class="p">:</span> <span class="n">dest</span><span class="p">)</span>
        <span class="p">}</span>
        <span class="o">.</span><span class="nf">onDelete</span><span class="p">(</span><span class="nv">perform</span><span class="p">:</span> <span class="n">deleteItems</span><span class="p">)</span>
      <span class="p">}</span>
      <span class="o">.</span><span class="nf">animation</span><span class="p">(</span><span class="o">.</span><span class="k">default</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="n">listItems</span><span class="p">)</span>
      <span class="o">.</span><span class="n">toolbar</span> <span class="p">{</span>
          <span class="kt">Button</span> <span class="p">{</span>
            <span class="n">newTitle</span> <span class="o">=</span> <span class="s">""</span>
            <span class="n">newValueText</span> <span class="o">=</span> <span class="s">""</span>
            <span class="n">showingAddDialog</span> <span class="o">=</span> <span class="kc">true</span>
          <span class="p">}</span> <span class="nv">label</span><span class="p">:</span> <span class="p">{</span>
            <span class="kt">Image</span><span class="p">(</span><span class="nv">systemName</span><span class="p">:</span> <span class="s">"plus"</span><span class="p">)</span>
          <span class="p">}</span>
      <span class="p">}</span>
      <span class="o">.</span><span class="nf">navigationTitle</span><span class="p">(</span><span class="s">"Items"</span><span class="p">)</span>
      <span class="o">.</span><span class="nf">alert</span><span class="p">(</span><span class="s">"Add Item"</span><span class="p">,</span> <span class="nv">isPresented</span><span class="p">:</span> <span class="n">$showingAddDialog</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">TextField</span><span class="p">(</span><span class="s">"Title"</span><span class="p">,</span> <span class="nv">text</span><span class="p">:</span> <span class="n">$newTitle</span><span class="p">)</span>
        <span class="kt">TextField</span><span class="p">(</span><span class="s">"Value"</span><span class="p">,</span> <span class="nv">text</span><span class="p">:</span> <span class="n">$newValueText</span><span class="p">)</span>
        <span class="kt">Button</span><span class="p">(</span><span class="s">"Add"</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span> <span class="k">let</span> <span class="nv">intValue</span> <span class="o">=</span> <span class="kt">Int</span><span class="p">(</span><span class="n">newValueText</span><span class="o">.</span><span class="nf">trimmingCharacters</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="o">.</span><span class="n">whitespacesAndNewlines</span><span class="p">)),</span> <span class="o">!</span><span class="n">newTitle</span><span class="o">.</span><span class="nf">trimmingCharacters</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="o">.</span><span class="n">whitespacesAndNewlines</span><span class="p">)</span><span class="o">.</span><span class="n">isEmpty</span> <span class="p">{</span>
            <span class="n">listItems</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="kt">Item</span><span class="p">(</span><span class="nv">title</span><span class="p">:</span> <span class="n">newTitle</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="n">intValue</span><span class="p">))</span>
          <span class="p">}</span>
        <span class="p">}</span>
        <span class="kt">Button</span><span class="p">(</span><span class="s">"Cancel"</span><span class="p">,</span> <span class="nv">role</span><span class="p">:</span> <span class="o">.</span><span class="n">cancel</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
      <span class="p">}</span> <span class="nv">message</span><span class="p">:</span> <span class="p">{</span>
        <span class="kt">Text</span><span class="p">(</span><span class="s">"Enter a title and a numeric value."</span><span class="p">)</span>
      <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="kd">func</span> <span class="nf">deleteItems</span><span class="p">(</span><span class="n">at</span> <span class="nv">offsets</span><span class="p">:</span> <span class="kt">IndexSet</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">listItems</span><span class="o">.</span><span class="nf">remove</span><span class="p">(</span><span class="nv">atOffsets</span><span class="p">:</span> <span class="n">offsets</span><span class="p">)</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="listを使わずforeachだけでdragndropが出来るのだが実装が複雑そうだ">Listを使わずForEachだけでDrag’N’Dropが出来るのだが実装が複雑そうだ。</h3>

<p><a href="https://qiita.com/chanzmao/items/d96e640a34022545da9b">【SwiftUI】シンプルにドラッグで並び替えできる List を 作りたい #Swift - Qiita</a></p>]]></content><author><name>Tana Gone</name></author><category term="SwiftUI" /><summary type="html"><![CDATA[Drag’N’Dropで配列に要素を追加したり、要素を削除したり、要素の順番を変える方法を探る。以下のコードではalart Dialogの出し方も記載されている。]]></summary></entry><entry><title type="html">書評 つくりながら学ぶ深層強化学習(マイナビ、20180625)</title><link href="/diary/bookreview-deeprl/" rel="alternate" type="text/html" title="書評 つくりながら学ぶ深層強化学習(マイナビ、20180625)" /><published>2026-01-10T17:59:35+09:00</published><updated>2026-01-10T17:59:35+09:00</updated><id>/diary/bookreview-deeprl</id><content type="html" xml:base="/diary/bookreview-deeprl/"><![CDATA[<p>映画The Thinking Gameを見たのと斎藤康毅氏のゼロから作るDeep Learning6 LLM編(公開Review版)を読んで深層強化学習を知りたくなった。そこで、この本を図書館で借りてきた。</p>

<p>第一印象はムズい本だというものだったが、ソースコードを追う内に解ってきた。状態s、行動aは理解が容易なのだが、方策π、パラメータθが解らん。これが最初に出てきて、気になって読み進めないのだ。</p>

<p>しかし、コードを解読していくと著者が難しい概念を頑張って解説していると気がついた。強化学習はLLMで採用されているTransformerやSelf-Attentionよりムズい。</p>

<p>まず3x3の迷路を方策勾配法で解くコードの解読をするまで、本の文字の部分が意味不明だった。サポートページに式の正誤が掲載されている事に気が付かないと、数式も意味不明だ。</p>

<p>πとはテーブルの事でセルには確率が入っている。テーブルの縦軸(行)は状態(迷路の位置)で横軸(列)は行動の種別(上右下左)だ。θはSoftmaxを使ってπに変換されるものでNNのOutputの様なもの、あるいはWeightの様なものだ。誤解を招く表現が本の中ではなされていてtheta_0 = [[NAN, 1, 1,…といったコードを見て1に何か意味があるのだと間違った解釈をしてしまった。1の部分は乱数を使って決めても良いのだ。</p>

<p>3x3の迷路問題だけでなくAtari Breakoutゲームの攻略アルゴリズムも掲載されている。Laptopで11.5hrで学習完了しAWS GPUインスタンスを使うと3hrだったと紹介されている。Laptopは16GBメモリ、core i7 7500@2.7GHz GPU無しモデルでAWSはオハイオリージョンを使い0.9ドル/hrのコストで走らせている(原稿執筆当時)。pp. 224 - 225</p>

<p>強化学習の歴史は古く、学習するネズミ(Skinnerの実験)の様子から機械も学習可能だとの連想に繋がって行った様だ。</p>

<p><img src="/images/2026/RL.png" alt="囲碁AI歴史" style="zoom:33%;" /></p>

<p>補足:</p>

<p>オリジナルのソースはIPython環境での実行を想定している。次のようなコードはTerminal環境では動作しない。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">animate</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
    <span class="sh">'''</span><span class="s">フレームごとの描画内容</span><span class="sh">'''</span>
    <span class="n">state</span> <span class="o">=</span> <span class="n">state_history</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>  <span class="c1"># 現在の場所を描く
</span>    <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="n">state</span> <span class="o">%</span> <span class="mi">3</span><span class="p">)</span> <span class="o">+</span> <span class="mf">0.5</span>  <span class="c1"># 状態のx座標は、3で割った余り+0.5
</span>    <span class="n">y</span> <span class="o">=</span> <span class="mf">2.5</span> <span class="o">-</span> <span class="nf">int</span><span class="p">(</span><span class="n">state</span> <span class="o">/</span> <span class="mi">3</span><span class="p">)</span>  <span class="c1"># y座標は3で割った商を2.5から引く
</span>    <span class="n">line</span><span class="p">.</span><span class="nf">set_data</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
    <span class="nf">return </span><span class="p">(</span><span class="n">line</span><span class="p">,)</span>
<span class="c1">#　初期化関数とフレームごとの描画関数を用いて動画を作成する
</span><span class="n">anim</span> <span class="o">=</span> <span class="n">animation</span><span class="p">.</span><span class="nc">FuncAnimation</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">animate</span><span class="p">,</span> <span class="n">init_func</span><span class="o">=</span><span class="n">init</span><span class="p">,</span> <span class="n">frames</span><span class="o">=</span><span class="nf">len</span><span class="p">(</span>
    <span class="n">state_history</span><span class="p">),</span> <span class="n">interval</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span> <span class="n">repeat</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>

<span class="nc">HTML</span><span class="p">(</span><span class="n">anim</span><span class="p">.</span><span class="nf">to_jshtml</span><span class="p">())</span>
</code></pre></div></div>

<p>ソースが作成された時代(2018)以来matplotlibが改良されており2箇所の変更で動画を保存できる。不思議な事にソース中にpillowのimportが不要だ。set_dataメソッドの引数がscalarからlistへ変更しなと下記のエラーが発生する。</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-    line.set_data<span class="o">(</span>x, y<span class="o">)</span>
+    line.set_data<span class="o">([</span>x], <span class="o">[</span>y]<span class="o">)</span>

- HTML<span class="o">(</span>anim.to_jshtml<span class="o">())</span>
+ anim.save<span class="o">(</span><span class="nv">filename</span><span class="o">=</span><span class="s2">"maze_pgrad.gif"</span>, <span class="nv">writer</span><span class="o">=</span><span class="s2">"pillow"</span><span class="o">)</span>
</code></pre></div></div>

<p><img src="/images/2026/maze_pgrad.gif" alt="方策勾配法" style="zoom:33%;" /></p>

<p><a href="https://matplotlib.org/stable/users/explain/animations/animations.html">Animations using Matplotlib — Matplotlib 3.10.8 documentation</a></p>

<pre><code class="language-error">Traceback (most recent call last):

...
  File "/Users/tanaka/Documents/junk/python/test01/maze_pgrad.py", line 226, in animate
    line.set_data(x, y)
    ~~~~~~~~~~~~~^^^^^^
  File "/Users/tanaka/Documents/junk/python/test01/lib/python3.13/site-packages/matplotlib/lines.py", line 680, in set_data
    self.set_xdata(x)
    ~~~~~~~~~~~~~~^^^
  File "/Users/tanaka/Documents/junk/python/test01/lib/python3.13/site-packages/matplotlib/lines.py", line 1304, in set_xdata
    raise RuntimeError('x must be a sequence')
RuntimeError: x must be a sequence

...
</code></pre>

<h3 id="強化学習とは">強化学習とは?</h3>

<p>AIが経験から学ぶアルゴリズム。報酬をなるべく低コストで得る手法を学ぶアルゴリズム。アルゴリズムを採用すると最低コストの手法が得られる訳では無いが、少なくとも人間よりも賢いアルゴリズムである。(アルファ碁解体新書、初版 pp. 122)</p>

<p>e.g.</p>

<ol>
  <li>囲碁の盤面の次の一手は最善とは限らないが、人間が考える一手よりもベターなものが強化学習から得られる。</li>
  <li>自動運転の判断は最善とは限らないが、人間の運転よりは安全。</li>
</ol>

<p>「意義あるDRL」<a href="https://arxiv.org/abs/1709.06560">Deep Reinforcement Learning that Matters</a>のアブストラクトには世間に流布されている報告には再現性に乏しい報告があるので、再現性を担保するためのガイドラインの提案がなされている。アルゴリズムの中に乱数が採用されているので厳密な再現性は元々無いのだ。(pp. 236)</p>

<h3 id="変更点">変更点</h3>

<p>本の出版後の2022年にPython Package Gymのメンテナンスが行われなくなり、Farama Foundationが新たにGymnasium Packageのメンテを始めている。</p>

<p><a href="https://farama.org/Announcing-The-Farama-Foundation">Announcing The Farama Foundation - The future of open source reinforcement learning: The Farama Foundation</a></p>

<p>そのため本に掲載のソースは動かなくなっている。</p>

<p><a href="https://github.com/YutaroOgawa/Deep-Reinforcement-Learning-Book">YutaroOgawa/Deep-Reinforcement-Learning-Book: 書籍「つくりながら学ぶ！深層強化学習」のサポートリポジトリです</a></p>

<p>GymからGymnasiumへの移行ガイドが用意されている。</p>

<p><a href="https://gymnasium.farama.org/introduction/migration_guide/">Gym Migration Guide - Gymnasium Documentation</a></p>

<p>必要なPackageのInstallコマンドは</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python <span class="nt">-m</span> pip <span class="nb">install</span> <span class="s2">"gymnasium[classic-control]"</span>
</code></pre></div></div>
<p>や</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python <span class="nt">-m</span> pip <span class="nb">install</span> <span class="s2">"gymnasium[atari]"</span>
python <span class="nt">-m</span> pip <span class="nb">install </span>ale-py
</code></pre></div></div>
<p>であり
Agentが動き回るEnvironmentを作るコードは</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ENV</span> <span class="o">=</span> <span class="sh">"</span><span class="s">ALE/Breakout-v5</span><span class="sh">"</span>
<span class="n">env</span> <span class="o">=</span> <span class="n">gym</span><span class="p">.</span><span class="nf">make</span><span class="p">(</span><span class="n">ENV</span><span class="p">,</span> <span class="n">render_mode</span><span class="o">=</span><span class="sh">"</span><span class="s">rgb_array</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>

<p>や</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ENV</span> <span class="o">=</span> <span class="sh">"</span><span class="s">CartPole-v1</span><span class="sh">"</span>
<span class="n">env</span> <span class="o">=</span> <span class="n">gym</span><span class="p">.</span><span class="nf">make</span><span class="p">(</span><span class="n">ENV</span><span class="p">,</span> <span class="n">render_mode</span><span class="o">=</span><span class="sh">"</span><span class="s">rgb_array</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>

<p>となってる。こういった情報は次の掲示板で拾った。Gymnasiumの公式ページでAtariゲームのENV変数の与え方を探したが今のところ発見できない。</p>

<p><a href="https://community.latenode.com/t/cannot-find-atari-breakout-environment-in-gym-library/33102/3">Cannot find Atari Breakout environment in Gym library - Other Questions / OpenAI - Latenode Official Community</a></p>

<p>なお、Breakoutを使った学習プログラムの出発点は次の様になる。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="n">gymnasium</span> <span class="k">as</span> <span class="n">gym</span>
<span class="kn">import</span> <span class="n">ale_py</span>

<span class="n">ENV</span> <span class="o">=</span> <span class="sh">"</span><span class="s">ALE/Breakout-v5</span><span class="sh">"</span>

<span class="n">env</span> <span class="o">=</span> <span class="n">gym</span><span class="p">.</span><span class="nf">make</span><span class="p">(</span><span class="n">ENV</span><span class="p">,</span> <span class="n">render_mode</span><span class="o">=</span><span class="sh">"</span><span class="s">rgb_array</span><span class="sh">"</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">env</span><span class="p">.</span><span class="n">observation_space</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">env</span><span class="p">.</span><span class="n">action_space</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">env</span><span class="p">.</span><span class="n">unwrapped</span><span class="p">.</span><span class="nf">get_action_meanings</span><span class="p">())</span>

<span class="n">observation</span><span class="p">,</span> <span class="n">info</span> <span class="o">=</span> <span class="n">env</span><span class="p">.</span><span class="nf">reset</span><span class="p">()</span>

<span class="n">frame</span> <span class="o">=</span> <span class="n">env</span><span class="p">.</span><span class="nf">render</span><span class="p">()</span>      <span class="c1"># ← 画像はここから取る
</span><span class="n">plt</span><span class="p">.</span><span class="nf">imshow</span><span class="p">(</span><span class="n">frame</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">axis</span><span class="p">(</span><span class="sh">"</span><span class="s">off</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>

<span class="n">env</span><span class="p">.</span><span class="nf">close</span><span class="p">()</span>
</code></pre></div></div>

<div align="center"><img src="/images/2026/Breakout_start.png" alt="Breakout_start" style="zoom:50%;" /></div>]]></content><author><name>Tana Gone</name></author><category term="diary" /><summary type="html"><![CDATA[映画The Thinking Gameを見たのと斎藤康毅氏のゼロから作るDeep Learning6 LLM編(公開Review版)を読んで深層強化学習を知りたくなった。そこで、この本を図書館で借りてきた。]]></summary></entry><entry><title type="html">RubyプログラマのためのPytorchの始め方</title><link href="/ruby/rubypytorch/" rel="alternate" type="text/html" title="RubyプログラマのためのPytorchの始め方" /><published>2026-01-04T06:43:01+09:00</published><updated>2026-01-04T06:43:01+09:00</updated><id>/ruby/rubypytorch</id><content type="html" xml:base="/ruby/rubypytorch/"><![CDATA[<p>Rubyではbundleコマンドを使ってプロジェクトを作る。Pythonではvenvモジュールを使えばプロジェクトを作ることが出来る</p>

<h3 id="1-rubyプロジェクト作り方">1. Rubyプロジェクト作り方</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$bundle</span> init
<span class="nv">$echo</span> <span class="s2">"gem 'mysql2'"</span> <span class="o">&gt;</span> Gemfile
<span class="nv">$bundle</span> config <span class="nb">set </span>path vendor
<span class="nv">$bundle</span> <span class="nb">install
</span>Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Fetching bigdecimal 4.0.1
Installing bigdecimal 4.0.1 with native extensions
Fetching mysql2 0.5.7
Installing mysql2 0.5.7 with native extensions
Bundle <span class="nb">complete</span><span class="o">!</span> 1 Gemfile dependency, 3 gems now installed.
Bundled gems are installed into <span class="sb">`</span>./vendor<span class="sb">`</span>
<span class="nv">$echo</span> <span class="s2">"require 'mysql2'"</span> <span class="o">&gt;</span> a.rb
<span class="nv">$bundle</span> <span class="nb">exec </span>ruby a.rb <span class="c"># no error</span>
</code></pre></div></div>

<p>errorの例</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ruby</span> a.rb
&lt;internal:/opt/homebrew/Cellar/ruby/3.4.2/lib/ruby/3.4.0/rubygems/core_ext/kernel_require.rb&gt;:136:in <span class="s1">'Kernel#require'</span>: cannot load such file <span class="nt">--</span> mysql2 <span class="o">(</span>LoadError<span class="o">)</span>
...
</code></pre></div></div>

<h3 id="2-pythonプロジェクトの作り方">2. Pythonプロジェクトの作り方</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$mkdir</span> workingTree <span class="p">;</span> <span class="nb">cd </span>workingTree<span class="p">;</span> python <span class="nt">-m</span> venv <span class="nb">.</span>
<span class="nv">$source</span> bin/activate
<span class="nv">$python</span> <span class="nt">-m</span> pip <span class="nb">install </span>numpy
<span class="nv">$echo</span> <span class="s2">"import numpy as np
x = np.array([1, 2, 3])
print(str(x))
"</span> <span class="o">&gt;</span> a.py
<span class="nv">$python</span> a.py <span class="c"># [1 2 3]</span>
<span class="nv">$deactivate</span>
</code></pre></div></div>

<h3 id="3-python依存パッケージの確認">3. Python依存パッケージの確認</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$pip</span> freeze <span class="o">&gt;</span> requirements.txt
</code></pre></div></div>
<p>依存ファイルリストを使ってインストール</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$python</span> <span class="nt">-m</span> pip <span class="nb">install</span> <span class="nt">-r</span> requirements.txt
</code></pre></div></div>
<p>PytorchをInstallすればMetal対応のが自動的にInstallされる。約500MBのDiskを消費する。</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">(</span>test02<span class="o">)</span> <span class="o">[</span>13675@5:13]<span class="nv">$python</span>
Python 3.13.2 <span class="o">(</span>main, Feb  4 2025, 14:51:09<span class="o">)</span> <span class="o">[</span>Clang 16.0.0 <span class="o">(</span>clang-1600.0.26.6<span class="o">)]</span> on darwin
Type <span class="s2">"help"</span>, <span class="s2">"copyright"</span>, <span class="s2">"credits"</span> or <span class="s2">"license"</span> <span class="k">for </span>more information.
<span class="o">&gt;&gt;&gt;</span> import torch
<span class="o">&gt;&gt;&gt;</span> import numpy as np
... <span class="c"># create a 3D tensor from NumPy array</span>
... ary3d <span class="o">=</span> np.array<span class="o">([[[</span>1, 2], <span class="o">[</span>3, 4]],
...                   <span class="o">[[</span>5, 6], <span class="o">[</span>7, 8]]]<span class="o">)</span>
... tensor3d_2 <span class="o">=</span> torch.tensor<span class="o">(</span>ary3d<span class="o">)</span>  <span class="c"># Copies NumPy array</span>
<span class="o">&gt;&gt;&gt;</span> print<span class="o">(</span>tensor3d_2<span class="o">)</span>
tensor<span class="o">([[[</span>1, 2],
         <span class="o">[</span>3, 4]],

        <span class="o">[[</span>5, 6],
         <span class="o">[</span>7, 8]]]<span class="o">)</span>
<span class="o">&gt;&gt;&gt;</span> print<span class="o">(</span>torch.backends.mps.is_available<span class="o">())</span> <span class="c"># Metal Performance Shader</span>
... print<span class="o">(</span>torch.__version__<span class="o">)</span>
True
2.9.1
<span class="o">&gt;&gt;&gt;</span> import os
<span class="o">&gt;&gt;&gt;</span> os.system<span class="o">(</span><span class="s1">'du -sh'</span><span class="o">)</span>
543M	<span class="nb">.</span>
</code></pre></div></div>

<p><a href="https://github.com/rasbt/LLMs-from-scratch/blob/main/appendix-A/01_main-chapter-code/code-part1.ipynb">LLMs-from-scratch/appendix-A/01_main-chapter-code/code-part1.ipynb at main · rasbt/LLMs-from-scratch</a></p>

<p><a href="https://sebastianraschka.com/blog/2020/numpy-intro.html">Scientific Computing in Python: Introduction to NumPy and Matplotlib: Sebastian Raschka, PhD</a></p>

<p><a href="https://docs.pytorch.org/docs/stable/index.html">PyTorch documentation — PyTorch 2.9 documentation</a></p>]]></content><author><name>Tana Gone</name></author><category term="Ruby" /><summary type="html"><![CDATA[Rubyではbundleコマンドを使ってプロジェクトを作る。Pythonではvenvモジュールを使えばプロジェクトを作ることが出来る]]></summary></entry><entry><title type="html">macOSアプリをアプリを起動したときに、Window Sizeを起動毎に同じにする方法</title><link href="/swiftui/macoswindow-size/" rel="alternate" type="text/html" title="macOSアプリをアプリを起動したときに、Window Sizeを起動毎に同じにする方法" /><published>2025-12-24T10:24:17+09:00</published><updated>2025-12-24T10:24:17+09:00</updated><id>/swiftui/macoswindow-size</id><content type="html" xml:base="/swiftui/macoswindow-size/"><![CDATA[<p>App起動時にNSWindowへのインスタンスを取得しsetConterntSizeメソッドを呼び出せば良い</p>
<h3 id="frameモディファイアで設定できるminwidth-minheighはwindow-resize時には有効なのだが">frameモディファイアで設定できるminWidth, minHeighはWindow Resize時には有効なのだが…</h3>

<p>AppKitでは出来る起動時のWindow Size指定がSwiftUI@macOS 26では出来ない様だ。</p>

<div align="center"><img src="/images/2025/fixedSizeWindow.gif" alt="fixedSizeWindow" style="zoom:50%;" /></div>

<h3 id="app起動時にnswindowのインスタンスを取得">App起動時にNSWindowのインスタンスを取得</h3>

<p>起動の順番はApp▶️Scene▶️ContentView。ContentViewがWindowを生成する直前(onAppearイベント)にNSWindowのインスタンスが取得できる。</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">SwiftUI</span>
<span class="kd">import</span> <span class="kt">AppKit</span>
<span class="kd">@main</span>
<span class="kd">struct</span> <span class="kt">Bg_GeometryApp</span><span class="p">:</span> <span class="kt">App</span> <span class="p">{</span>
  <span class="k">var</span> <span class="nv">body</span><span class="p">:</span> <span class="kd">some</span> <span class="kt">Scene</span> <span class="p">{</span>
    <span class="kt">WindowGroup</span> <span class="p">{</span>
      <span class="kt">ContentView</span><span class="p">()</span>
        <span class="o">.</span><span class="n">onAppear</span> <span class="p">{</span>
          <span class="kt">DispatchQueue</span><span class="o">.</span><span class="n">main</span><span class="o">.</span><span class="k">async</span> <span class="p">{</span>
            <span class="k">if</span> <span class="k">let</span> <span class="nv">window</span> <span class="o">=</span> <span class="kt">NSApplication</span><span class="o">.</span><span class="n">shared</span><span class="o">.</span><span class="n">windows</span><span class="o">.</span><span class="n">first</span> <span class="p">{</span>
              <span class="k">let</span> <span class="nv">fixedSize</span> <span class="o">=</span> <span class="kt">NSSize</span><span class="p">(</span><span class="nv">width</span><span class="p">:</span> <span class="mi">500</span><span class="p">,</span> <span class="nv">height</span><span class="p">:</span> <span class="mi">200</span><span class="p">)</span>
              <span class="n">window</span><span class="o">.</span><span class="nf">setContentSize</span><span class="p">(</span><span class="n">fixedSize</span><span class="p">)</span>
<span class="c1">//              window.center()</span>
            <span class="p">}</span>
          <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="おまけ-起動後にwindowサイズを制限する">おまけ: 起動後にWindowサイズを制限する</h3>

<p>frameモディファイアでidealWidth, idealHeightを設定しても起動時のWindowサイズは固定できない。下記のコードではWindowサイズをResize時にwindowSizeプロパティに設定するコードも合わせて加えられている。
<br />
frameが返すViewのサイズ、つまりWindow全体に広がったView(maxWidht: .infinity, maxHeight: .infinity)のサイズはViewのbackgroundにあるGeometryReader(これもView)のサイズがそれだ。</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">import</span> <span class="kt">SwiftUI</span>
<span class="kd">struct</span> <span class="kt">ContentView</span><span class="p">:</span> <span class="kt">View</span> <span class="p">{</span>
  <span class="kd">@State</span> <span class="k">var</span> <span class="nv">windowSize</span><span class="p">:</span> <span class="kt">CGSize</span> <span class="o">=</span> <span class="o">.</span><span class="n">zero</span>
  <span class="k">var</span> <span class="nv">body</span><span class="p">:</span> <span class="kd">some</span> <span class="kt">View</span> <span class="p">{</span>
    <span class="kt">Text</span><span class="p">(</span><span class="s">"Fixed window size: </span><span class="se">\(</span><span class="kt">String</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="s">"%.0f %.0f"</span><span class="p">,</span> <span class="n">windowSize</span><span class="o">.</span><span class="n">width</span><span class="p">,</span> <span class="n">windowSize</span><span class="o">.</span><span class="n">height</span><span class="p">)</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
      <span class="o">.</span><span class="nf">frame</span><span class="p">(</span><span class="nv">minWidth</span><span class="p">:</span> <span class="mi">500</span><span class="p">,</span> <span class="nv">maxWidth</span><span class="p">:</span> <span class="o">.</span><span class="n">infinity</span><span class="p">,</span> <span class="nv">minHeight</span><span class="p">:</span> <span class="mi">200</span><span class="p">,</span> <span class="nv">maxHeight</span><span class="p">:</span> <span class="o">.</span><span class="n">infinity</span><span class="p">)</span>
<span class="c1">//      .frame(minWidth: 500, idealWidth: 500, maxWidth: .infinity, minHeight: 200,</span>
<span class="c1">//             idealHeight: 200, maxHeight: .infinity)</span>
      <span class="o">.</span><span class="nf">background</span><span class="p">(</span>
        <span class="kt">GeometryReader</span> <span class="p">{</span> <span class="n">geometry</span> <span class="k">in</span>
          <span class="kt">Color</span><span class="o">.</span><span class="n">blue</span>
            <span class="o">.</span><span class="nf">onChange</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="n">geometry</span><span class="o">.</span><span class="n">size</span><span class="p">)</span> <span class="p">{</span> <span class="n">_</span><span class="p">,</span> <span class="n">newSize</span> <span class="k">in</span>
              <span class="nf">print</span><span class="p">(</span><span class="s">"window size:</span><span class="se">\(</span><span class="n">newSize</span><span class="o">.</span><span class="n">width</span><span class="se">)</span><span class="s"> </span><span class="se">\(</span><span class="n">newSize</span><span class="o">.</span><span class="n">height</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
              <span class="n">windowSize</span> <span class="o">=</span> <span class="n">newSize</span>
            <span class="p">}</span>
        <span class="p">}</span>
      <span class="p">)</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>Tana Gone</name></author><category term="SwiftUI" /><summary type="html"><![CDATA[App起動時にNSWindowへのインスタンスを取得しsetConterntSizeメソッドを呼び出せば良い frameモディファイアで設定できるminWidth, minHeighはWindow Resize時には有効なのだが…]]></summary></entry><entry><title type="html">Linux Boxの起動ディスク交換</title><link href="/ruby/linux-box-backup/" rel="alternate" type="text/html" title="Linux Boxの起動ディスク交換" /><published>2025-12-20T11:11:00+09:00</published><updated>2025-12-20T11:11:00+09:00</updated><id>/ruby/linux-box-backup</id><content type="html" xml:base="/ruby/linux-box-backup/"><![CDATA[<h3 id="haltしたlinux-boxをbackupして新しいdiskにrestoreしたその時の作業を記録しておく">haltしたLinux BoxをBackupして新しいDiskにRestoreした。その時の作業を記録しておく。</h3>

<p>Linux BoxのBootドライブ兼Rootドライブ120GBのシステムバックアップ/リストアを行った。Linux BoxのRootファイルシステムはインストール直後という事もあって7GBしかDiskを消費していない。Linux BoxからDiskを取り外し、SATA-USB3変換アダプタを使ってもう一台のLinux Boxのdd, dd+gzip, partclone, partclone+gzipを使ってバックアップファイルを作成し、ファイルの大きさを比較してみた。4種の最後の方法が劇的にファイルサイズが小さい。</p>

<h3 id="バックアップコマンドddpartcloneの比較">バックアップコマンドdd、partcloneの比較</h3>
<p>どんなパーティション・スキーム(スタイル)、ファイル・システムでもファイル化できるddコマンドにも弱点がある。</p>

<ol>
  <li>Disk容量と同じファイルが出来てしまう。USB Pendriveなら許容できるが、どでかいHDDをバックアップしようとするとどでかいファイルが出来てしまう。gzipを併用してもせいぜい半分にしかサイズを縮小できない。</li>
  <li>リストアするには同じサイズのDiskか、更に大きい容量のDiskを用意せざるをえない。</li>
</ol>

<p>partcloneは大抵のソースファイル・システム(バックアップ元のパーティションのファイル・システム)に対応し、ntfs、hfs+、apfsを読み出して、Imageファイル化できる。もちろんImageファイルの書き戻しに対応している。弱点は</p>

<ol>
  <li>
    <p>Diskのパーティション・スキームを保存しない。fdiskでスキーム情報をテキストファイル化してImageと共に保存しておけばスキームの再現ができるのでリストアが簡単にできる。システムが起動する際にDisk-IDを元にRootファイルシステム が格納されたパーティションを探すBoot Loadもあるのでスキーム情報が無ければシステムディスクをリストアできないという事態が生じてしまう。
スキーム情報とは次のパーティション情報をテキスト化したものである。</p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$sudo</span> fdisk /dev/sda
   
Welcome to fdisk <span class="o">(</span>util-linux 2.38.1<span class="o">)</span><span class="nb">.</span>
Changes will remain <span class="k">in </span>memory only, <span class="k">until </span>you decide to write them.
Be careful before using the write command.
   
Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>: p
   
Disk /dev/sda: 476.94 GiB, 512110190592 bytes, 1000215216 sectors
Disk model:
Units: sectors of 1 <span class="k">*</span> 512 <span class="o">=</span> 512 bytes
Sector size <span class="o">(</span>logical/physical<span class="o">)</span>: 512 bytes / 4096 bytes
I/O size <span class="o">(</span>minimum/optimal<span class="o">)</span>: 4096 bytes / 4096 bytes
Disklabel <span class="nb">type</span>: dos
Disk identifier: 0x42208722
   
Device     Boot   Start        End   Sectors   Size Id Type
/dev/sda1          8192    1056767   1048576   512M  c W95 FAT32 <span class="o">(</span>LBA<span class="o">)</span>
/dev/sda2       1056768 1000215215 999158448 476.4G 83 Linux
   
Command <span class="o">(</span>m <span class="k">for </span><span class="nb">help</span><span class="o">)</span>:
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="同じソースをddして出来上がるターゲットファイルの大きさ比較">同じソースをddして出来上がるターゲット・ファイルの大きさ比較</h3>
<p>📅2025/10/28Tu
🔹dd
% sudo time dd if=/dev/sdb of=/mnt/win10/bkc.dd bs=16MB conv=sparse status=progress</p>

<table>
  <tbody>
    <tr>
      <td>$ dd if=/dev/sdb bs=16MB status=progress</td>
      <td>pigz &gt; /mnt/win10/bkp.img.gz</td>
    </tr>
  </tbody>
</table>

<p>pi@is ~ % ls -lh /mnt/win10
合計 182G
-rw-r–r– 1 root root 1.6K 10月 28 12:21 00memo.md
-rw-r–r– 1 root root 112G 10月 28 11:01 bkc.dd
-rw-r–r– 1 root root  69G 10月 28 10:33 bkp.dd.gz
drwx—— 2 root root  16K 10月 28 09:47 lost+found
-rw-r–r– 1 root root  198 10月 28 11:46 ti_lan.fdisk
-rw——- 1 root root  68M 10月 28 11:48 ti_lan_p1.img
-rw——- 1 root root 6.9G 10月 28 12:01 ti_lan_p2.img
-rw-r–r– 1 root root 2.2G 10月 28 11:54 ti_lan_p2.img.gz
pi@is ~ %
<a href="https://qiita.com/taiyodayo/items/7c60c9b3bc00b13baf43">「dd | gzip」 はそこまでだ！「dd | pigz」にするだけで20倍速くなった件 #Linux - Qiita</a></p>

<p>🔹Partclone 
pi@is ~ % sudo time  bash a.sh</p>
<pre><code class="language-bash:a.sh">partclone.ext4 -d -c -s /dev/sdb2 | pigz &gt; /mnt/win10/ti_lan_p2.img.gz
</code></pre>
<p>Partclone v0.3.17 http://partclone.org
Starting to clone device (/dev/sdb2) to image (-)
Reading Super Block
Calculating bitmap… Please wait…
Elapsed: 00:00:01, Remaining: 00:00:00, Completed: 100.00%
Total Time: 00:00:01, 100.00% completed!
done!
File system:  EXTFS
Device size:  119.5 GB = 29173110 Blocks
Space in use:   7.4 GB = 1801286 Blocks
Free Space:   112.1 GB = 27371824 Blocks
Block size:   4096 Byte
Elapsed: 00:01:20, Remaining: 00:00:00, Completed: 100.00%, Rate:   5.53GB/min,
current block:   28841362, total block:   29173110, Complete: 100.00%
Total Time: 00:01:20, Ave. Rate:    5.5GB/min, 100.00% completed!
Syncing… OK!
Partclone successfully cloned the device (/dev/sdb2) to the image (-)
Cloned successfully.
267.55user 10.68system 1:20.89elapsed 343%CPU (0avgtext+0avgdata 12356maxresident)k
15214360inputs+4490504outputs (9major+3999minor)pagefaults 0swaps</p>

<p><a href="https://linux-jp.org/?p=5068">「スマート」パーティションバックアップを作成するためのpartcloneの使用方法</a>
<br />🔸restore
gzip -c -d /mnt/win10/ti_lan_p2.img.gz | sudo partclone.ext4 -d -r -o /dev/sdb2</p>]]></content><author><name>Tana Gone</name></author><category term="Ruby" /><summary type="html"><![CDATA[haltしたLinux BoxをBackupして新しいDiskにRestoreした。その時の作業を記録しておく。]]></summary></entry></feed>