tag:blogger.com,1999:blog-305079252024-02-28T19:36:32.238+09:00bluewidz nota~ただのメモ置き場。なので、内容の正しさについての保証は一切ありませんよ~ copyright (c) 2006-2023 bluewidz, all rights reserved.bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.comBlogger275125tag:blogger.com,1999:blog-30507925.post-13636958317474707752023-11-12T11:59:00.000+09:002023-11-12T11:59:36.186+09:00PrivateGPTの使い方メモ<h1 class="section">はじめに</h1><br/>
PrivateGPTを試したのでメモ。PrivateGPTのドキュメントは<br/>
<a href="https://docs.privategpt.dev/">https://docs.privategpt.dev/</a><br/>
に公開されており、少なくともLinux環境かつGPUを利用する条件では、このドキュメント通りにインストールすると使えるようになります。
<p/>
<h1 class="section">使い方</h1><br/>
インストールが完了すると、
<pre class="code">
PGPT_PROFILES=local make run
</pre>
でローカル実行できます。具体的な実行コードはMakefileに記載されています。実行後、
http://localhost:8001/
にアクセスすると利用できます。
<p/>
ドキュメントをPrivateGPTに取り込むには、
<pre class="code">
PGPT_PROFILES=local make ingest /path/to/docments
</pre>
を実行します。<span class="code">8487440a6f8d135</span>のリビジョンのコードでは、コードを改変しない限りディレクトリしか指定できません。実行すると、ディレクトリにあるファイルが解析されてPrivateGPTに追加されます。実行するたびにファイル名が同じものを除いて追加されていきます。削除方法はPrivateGPTのドキュメントに記載されています。
<p/>
ドキュメントの取り込み時は単にサーバーを動かすときよりもGPUのメモリを使用するため、もしGPUのメモリが足りない場合は
<pre class="code">
CUDA_VISIBLE_DEVICES="" PGPT_PROFILES=local make ingest /path/to/docments
</pre>
のようにして、GPUを見えなくすればCPUで処理してくれます。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-48399982736080925212023-10-26T00:09:00.002+09:002023-10-26T00:10:58.658+09:00Diffusion MNIST その3<h1 class="section">はじめに</h1><br/>
<a href="https://bluewidz.blogspot.com/2023/10/diffusion-mnist.html">その1</a>で試したDiffusion MNISTについて、
ノイズの強さを表す時刻\(t\)をニューラルネットワークに伝えないとどうなるのかを見ていきます。
<p/>
<h1 class="section">方法</h1><br/>
<a href="https://github.com/MarceloGennari/diffusion_mnist">https://github.com/MarceloGennari/diffusion_mnist</a>
のConditionalUNetの\(t\)が関連する行、つまり、TemporalEmbedding部分をコメントアウトします。具体的には
<pre class="code">
class ConditionalUNet(UNet):
(省略)
def forward(self, x: Tensor, t: Tensor, label: Tensor) -> Tensor:
x0 = x #self.embedding1(x, t)
x1 = self.block1(x0)
x1 = self.label_emb1(x1, label)
#x1 = self.embedding2(x1, t)
x2 = self.block2(self.down1(x1))
x2 = self.label_emb2(x2, label)
#x2 = self.embedding3(x2, t)
crossed = self.label_emb3(self.block3(self.down2(x2)), label)
x3 = self.up1(self.attention1(crossed))
x4 = torch.cat([x2, x3], dim=1)
#x4 = self.embedding4(x4, t)
x5 = self.up2(self.label_emb4(self.block4(x4), label))
x6 = torch.cat([x5, x1], dim=1)
x6 = self.label_emb5(x6, label)
#x6 = self.embedding5(x6, t)
out = self.out(self.block5(x6))
return out
</pre>
とします。
<p/>
<h1 class="section">結果</h1><br/>
<a href="https://bluewidz.blogspot.com/2023/10/diffusion-mnist_22.html">その2</a>で試した時間刻みを100にしたバージョンをベースに比較します。左側がTemporalEmbeddingありで、右側がなしに対応します。
<style>
figcaption.bar {
color: #f0f0f0;
background-color: #505050;
display: table-caption;
caption-side: top;
width: 100%;
text-align: center;
}
</style>
<div class="separator" style="clear: both;">
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=50 TemporalEmbeddingあり</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPbsfuxE4sUq0BAthOE6xzKF2m4um1HIFrNvan9soJwcq4zrAgYYDTqaMrl6n_rgd4w7HC67ysh8kbsAvXveupsPWU8jWEuRVxL4axf-Wh0K3OQPJa9ypZWjC-kFaYtTJPJ0jGp0XO9ezb8mxG63ICUGHSiiO5FodEVAIrL9j6cVlYbejDIIvV8w/s600/generated_t50.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPbsfuxE4sUq0BAthOE6xzKF2m4um1HIFrNvan9soJwcq4zrAgYYDTqaMrl6n_rgd4w7HC67ysh8kbsAvXveupsPWU8jWEuRVxL4axf-Wh0K3OQPJa9ypZWjC-kFaYtTJPJ0jGp0XO9ezb8mxG63ICUGHSiiO5FodEVAIrL9j6cVlYbejDIIvV8w/s320/generated_t50.png"/></a>
</figure>
<figure style="display: inline-block; margin: 0">
<figcaption class="bar">t=50 TemporalEmbeddingなし</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG40r7-V9khqcrrvdowJ3naYpZfvwNW-1gqBD3Rw6PI0MvSXoNNagHzZj2X9cmjc4I392u4Z1tyDJMYfnELSrK1VsgMyVlPs9WwhsY7nqo82YRN01qAD_ZPf68RCX2bQqZ5_iaZ-7QZ5lvIT4HIKH1E4IWmLfzhRym4hb-da54qss3vR5WcNVHqA/s600/generated_t50_notime.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG40r7-V9khqcrrvdowJ3naYpZfvwNW-1gqBD3Rw6PI0MvSXoNNagHzZj2X9cmjc4I392u4Z1tyDJMYfnELSrK1VsgMyVlPs9WwhsY7nqo82YRN01qAD_ZPf68RCX2bQqZ5_iaZ-7QZ5lvIT4HIKH1E4IWmLfzhRym4hb-da54qss3vR5WcNVHqA/s320/generated_t50_notime.png"/></a>
</figure>
</div>
<p/>
<div class="separator" style="clear: both;">
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=0 TemporalEmbeddingあり</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXT9h1wTBdFQuu26XPI4VLzRKMxeZUfkOaDdVtYPcvydzPC6pCmgVfA14gNiNWXym1E2kN822ZTwaZuD-0mMDQ0IrJfO5lPedtz2BJSl70KH4ewDg6xvEuNK6DJx4EtnZKRTJbY9ny06cE1MBC2I-RgHXnPcVsXiM3hiTsiJ1DaNsnd0g3yy2Yxw/s600/generated_t0.png" style="display: block; padding: 0em 0; text-align: left;"><img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXT9h1wTBdFQuu26XPI4VLzRKMxeZUfkOaDdVtYPcvydzPC6pCmgVfA14gNiNWXym1E2kN822ZTwaZuD-0mMDQ0IrJfO5lPedtz2BJSl70KH4ewDg6xvEuNK6DJx4EtnZKRTJbY9ny06cE1MBC2I-RgHXnPcVsXiM3hiTsiJ1DaNsnd0g3yy2Yxw/s320/generated_t0.png"/></a>
</figure>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=0 TemporalEmbeddingなし</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYITQYZWSsYBmI_7ZbOxeSiA-nrVJHK2T8lswbkU-MfD3SnQhMvD-H8OqRxiUSaYcAMjp2rFTRWKfEdfT3B1jZCZDsrk8wdi8OUbUdB3Eq3JEJGlFw8Z6T1FnCBNLLW_YXIcoLR7qcYYZzsHjYf1oMhTy1q1IV4MrvBSqu3vSG-ef5kRV2VQi6Ug/s600/generated_t0_notime.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYITQYZWSsYBmI_7ZbOxeSiA-nrVJHK2T8lswbkU-MfD3SnQhMvD-H8OqRxiUSaYcAMjp2rFTRWKfEdfT3B1jZCZDsrk8wdi8OUbUdB3Eq3JEJGlFw8Z6T1FnCBNLLW_YXIcoLR7qcYYZzsHjYf1oMhTy1q1IV4MrvBSqu3vSG-ef5kRV2VQi6Ug/s320/generated_t0_notime.png"/></a>
</figure>
</div>
<p/>
<div class="separator" style="clear: both;">
TemporalEmbeddingなしの場合はノイズが多いように見えるので、画像の明るさをGIMPを使って上げたものが下図です。TemporalEmbeddingありではノイズが見えませんが、TemporalEmbeddingなしではノイズがはっきり見えるケースが多くなっています。<br/>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=0 TemporalEmbeddingあり</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKAxPJ_9An1DSE4Ha-LEyTWc-aI68s9ioNmjnLEx-MUZS-dm8OOMreLYScStdkCpbIAu2XTysQePp_l-Y44qrkwqephZYjXMSEhmbU7thIs0XvycOvNTXsuwlFk7kGFY7wDwZI22x9Oo88FjW2LDRzdaYp-IkCH5dUYXg6hRtgt8dr72JoYvyYcA/s600/generated_t0_time.bright.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKAxPJ_9An1DSE4Ha-LEyTWc-aI68s9ioNmjnLEx-MUZS-dm8OOMreLYScStdkCpbIAu2XTysQePp_l-Y44qrkwqephZYjXMSEhmbU7thIs0XvycOvNTXsuwlFk7kGFY7wDwZI22x9Oo88FjW2LDRzdaYp-IkCH5dUYXg6hRtgt8dr72JoYvyYcA/s320/generated_t0_time.bright.png"/></a>
</figure>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=0 TemporalEmbeddingなし</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBIDpSdY7sNZoWAAZo-Dz9ouq_5VfOqjB1q_LVdVYA3TIBLWtZzFAlPW4025gUP7jReAa5Q6tJrSizJNZEnx4pJfTklyymnWIqvuvB2ZQoHqdL6NM_KQAbF7H6jQnCCP70JFLO_s5Hh1qatkWLVQ23C5eb2pSqasHVEVq3apJUcxUq8s_gm7Xdvw/s600/generated_t0_notime.bright.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBIDpSdY7sNZoWAAZo-Dz9ouq_5VfOqjB1q_LVdVYA3TIBLWtZzFAlPW4025gUP7jReAa5Q6tJrSizJNZEnx4pJfTklyymnWIqvuvB2ZQoHqdL6NM_KQAbF7H6jQnCCP70JFLO_s5Hh1qatkWLVQ23C5eb2pSqasHVEVq3apJUcxUq8s_gm7Xdvw/s320/generated_t0_notime.bright.png"/></a>
</figure>
</div>
<p/>
<h1 class="section">まとめ</h1><br/>
時刻の埋め込みは効果があるということを確認できました。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-35739094532935893312023-10-22T12:18:00.003+09:002023-10-26T00:09:46.374+09:00Diffusion MNIST その2<h1 class="section">はじめに</h1><br/>
<a href="https://bluewidz.blogspot.com/2023/10/diffusion-mnist.html">その1</a>で試したDiffusion MNISTについて、
ノイズを乗せるステップの細かさを粗くするとどうなるのかを見てみます。
<p/>
<h1 class="section">方法</h1><br/>
<a href="https://github.com/MarceloGennari/diffusion_mnist">https://github.com/MarceloGennari/diffusion_mnist</a>
をいくつか変更することで粗さを変えていきます。
<p/>
<h2 class="section">スケジュール変更</h2><br/>
DiffusionProcessの引数に渡すvariance_scheduleを変えていきます。
デフォルトでは、
<pre class="code">
variance_schedule = torch.linspace(1e-4, 0.01, steps=1000)
</pre>
となっています。これをパターンAでは
<pre class="code">
variance_schedule = torch.linspace(1e-4, 0.1, steps=100)
</pre>
と、パターンBでは
<pre class="code">
variance_schedule = torch.linspace(1e-4, 0.999, steps=10)
</pre>
とします。
<p/>
それぞれのスケジュールを使ったときのalphaは
<pre class="code">
[パターン デフォルト]
[0.99990, 0.99989, 0.99988, ... , 0.99001, 0.99000]
[パターン A]
[0.99990, 0.99889, 0.99788, ... , 0.90101, 0.90000]
[パターン B]
[0.99990, 0.88891, 0.77792, ... , 0.11199, 0.00100]
</pre>
となります。
<p/>
alpha_barは
<pre class="code">
[パターン デフォルト]
[0.9999, 0.9998, 0.9997, ... , 0.0064, 0.0063]
[パターン A]
[0.9999, 0.9988, 0.9967, ... , 0.0062, 0.0056]
[パターン B]
[9.9990e-01, 8.8882e-01, 6.9143e-01, ... , 9.5131e-04, 9.5130e-07]
</pre>
となります。ここで重要なことは、最初の時刻(ノイズが乗っていない)をt=0、最後の時刻(完全にノイズ)をt=1とするとき、alpha_barはt=0では1に近く、t=1では0に近くなるようにvariance_scheduleを決める必要があるということです。
各時刻tにおけるノイズの強さがalpha_barで決まり、t=1のときに完全にノイズになっていないと拡散プロセスの前提が崩れてしまうためです。
<p/>
実際、パターンAの
<pre class="code">
variance_schedule = torch.linspace(1e-4, 0.1, steps=100)
</pre>
を
<pre class="code">
variance_schedule = torch.linspace(1e-4, 0.01, steps=100)
</pre>
に変えると、alpha_bar の値は
<pre class="code">
0.99990, 0.99970, 0.99940, ... , 0.60857, 0.60248
</pre>
となりますが、この場合、数字の画像をうまく生成できません。
<p/>
<h2 class="section">学習時のtの値</h2><br/>
デフォルトでは<span class="code">main.py</span>の
<pre class="code">
t = torch.randint(0, 1000, (image.shape[0],))
</pre>
の1000のところを、パターンAでは100に、パターンBでは10にします。
<p/>
<h2 class="section">生成時のtの値</h2><br/>
デフォルトでは<span class="code">inference_unet.py</span>の
<pre class="code">
for t in trange(999, -1, -1):
</pre>
の999のところを、パターンAでは99に、パターンBでは9にします。刻む数が少なくなると(ステップの細かさを粗くすると)、その分だけ生成時間を短くできます。
<p/>
<h1 class="section">結果</h1><br/>
<style>
figcaption.bar {
color: #f0f0f0;
background-color: #505050;
display: table-caption;
caption-side: top;
width: 100%;
text-align: center;
}
</style>
<div class="separator" style="clear: both;">
デフォルトの設定ではこのようになります(<a href="https://bluewidz.blogspot.com/2023/10/diffusion-mnist.html">その1</a>の再掲)<br/>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=500</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu0_PQNN2q9e8Xuq7SLSmlWo0wKtflUJOjKH8EUhIxJhzU8iYBmy3dxkiNADcAfQuRtViY28Oz8c0AC-Yx6XJI_oHj5z9RghN9KFvTWBtnAuajezKse1fR1-C_vHwSlYJ6-lSXCTnGW1b6_Yd2q2Ev4BAUADJzdKlESLvsy15t4OqP0NLJjp16zw/s600/generated_t500.png" style="display: inline-block; padding: 0em 0; text-align: left; ">
<img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu0_PQNN2q9e8Xuq7SLSmlWo0wKtflUJOjKH8EUhIxJhzU8iYBmy3dxkiNADcAfQuRtViY28Oz8c0AC-Yx6XJI_oHj5z9RghN9KFvTWBtnAuajezKse1fR1-C_vHwSlYJ6-lSXCTnGW1b6_Yd2q2Ev4BAUADJzdKlESLvsy15t4OqP0NLJjp16zw/s320/generated_t500.png"/>
</a>
</figure>
<figure style="display: inline-block; margin: 0">
<figcaption class="bar">t=0</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLnrs36DtpqhObAE05xXWvfno-DfiF7d2M3bbOiMCMK3QKgWD9gVn8iZAPn6B2qG3j60VhLiXj8N2BVT6muXAnKE6k1aBFIAJAGedGWOk9oQ36wJaolWML_-t2u51ST5yfJ6CNdfisL7av_N9Xn_i2bI1VG5-yMTjGvgdN027yAP7_fsLxCFrunQ/s600/generated_t0.png" style="display: inline-block; padding: 0em 0; text-align: left; ">
<img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLnrs36DtpqhObAE05xXWvfno-DfiF7d2M3bbOiMCMK3QKgWD9gVn8iZAPn6B2qG3j60VhLiXj8N2BVT6muXAnKE6k1aBFIAJAGedGWOk9oQ36wJaolWML_-t2u51ST5yfJ6CNdfisL7av_N9Xn_i2bI1VG5-yMTjGvgdN027yAP7_fsLxCFrunQ/s320/generated_t0.png"/>
</a>
</figure>
</div>
<p/>
<div class="separator" style="clear: both;">
時刻を100個に刻んだパターンAでも特に変わりなく生成できています。<br/>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=50</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0cgUBQP_tIKMSv5uNWjhjFZAcAlu8fbNQGoJqiOSGf86CoAMfRyQLtWXV146B5t6LwdyO4gfzSI3CGq9vUoL1KsW-53RQKxU-B8bJVAiLxPL-_73rC91U49zlnI-gggoYLAOb5vTe_UarrMNkln3slDm2RGa9s3YJA5eD9a4Za6Bf5mD-wpdarg/s300/generated_t50.png" style="display: inline-block; padding: 1em 0; text-align: left; ">
<img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0cgUBQP_tIKMSv5uNWjhjFZAcAlu8fbNQGoJqiOSGf86CoAMfRyQLtWXV146B5t6LwdyO4gfzSI3CGq9vUoL1KsW-53RQKxU-B8bJVAiLxPL-_73rC91U49zlnI-gggoYLAOb5vTe_UarrMNkln3slDm2RGa9s3YJA5eD9a4Za6Bf5mD-wpdarg/s320/generated_t50.png"/>
</a>
</figure>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=0</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWM7hGp0x6xr-FqYrRkJpVz57M_d3ORHcL0kQDBLXJ0wZe8GBECrkuFdYoSajbUnTVGPqCd_uioR1BkF960DDipbrYiUxDuei1-91lCXZAwAuEq6xud9E9Zpa6qdf3HTxaUOfekgqTc0XpDeWnUjwrrPL1x0Cr34abWXVjj8qH8_CIqBH4kIKc0g/s300/generated_t0.png" style="display: inline-block; padding: 1em 0; text-align: left; ">
<img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWM7hGp0x6xr-FqYrRkJpVz57M_d3ORHcL0kQDBLXJ0wZe8GBECrkuFdYoSajbUnTVGPqCd_uioR1BkF960DDipbrYiUxDuei1-91lCXZAwAuEq6xud9E9Zpa6qdf3HTxaUOfekgqTc0XpDeWnUjwrrPL1x0Cr34abWXVjj8qH8_CIqBH4kIKc0g/s320/generated_t0.png"/>
</a>
</figure>
</div>
<p/>
<div class="separator" style="clear: both;">
時刻を10個に刻んだパターンBだと、多少ノイズが残ってしまいますが、生成できないというほどではありません。<br/>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=5</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV4UBOJ2NMtKAFOqfe43KmiY-oIqPoA_mdrJXTk5kr1qxc5cIS6ZV-KuY1Ct6E19POF-HUJtrmxFi7XN1LLsAHrkYFI2t_4Zttt89C3VYDUh8BDI-NqyZNATNl33rQ-WGW2tBfxcONxZY1hXg-Mj0OEyg898nlybrxgQu6EUO448sOGQdJtsigtg/s300/generated_t5.png" style="display: inline-block; padding: 1em 0; text-align: left; ">
<img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV4UBOJ2NMtKAFOqfe43KmiY-oIqPoA_mdrJXTk5kr1qxc5cIS6ZV-KuY1Ct6E19POF-HUJtrmxFi7XN1LLsAHrkYFI2t_4Zttt89C3VYDUh8BDI-NqyZNATNl33rQ-WGW2tBfxcONxZY1hXg-Mj0OEyg898nlybrxgQu6EUO448sOGQdJtsigtg/s320/generated_t5.png"/>
</a>
</figure>
<figure style="display: inline-block; margin: 0;">
<figcaption class="bar">t=0</figcaption>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1Chc7Ma1S8CXw_Jz5oeFdjFO0XEbyYwYQZLHX-c3n2gFPwuia3fUmxB64j0-TV32LojnuUrGtiVzZa4dSwvMxcCmTGmkxtmWMyTS0prmkvM07NW5eqQTZbqQf6bFCkfuJUiLeb2sIvBAtYa5zo0KDXJH1yCLL1W-zuslsQYlPcyYmAoSzkxu-8A/s300/generated_t0.png" style="display: inline-block; padding: 1em 0; text-align: left; ">
<img alt="" border="0" width="240" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1Chc7Ma1S8CXw_Jz5oeFdjFO0XEbyYwYQZLHX-c3n2gFPwuia3fUmxB64j0-TV32LojnuUrGtiVzZa4dSwvMxcCmTGmkxtmWMyTS0prmkvM07NW5eqQTZbqQf6bFCkfuJUiLeb2sIvBAtYa5zo0KDXJH1yCLL1W-zuslsQYlPcyYmAoSzkxu-8A/s320/generated_t0.png"/>
</a>
</figure>
</div>
<p/>
<h1 class="section">まとめ</h1><br/>
デフォルトの1000ステップではなくても、MNIST程度なら生成できることが分かりました。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-30984255994061574192023-10-15T19:26:00.004+09:002023-10-21T14:51:47.550+09:00Diffusion MNIST<h1 class="section">はじめに</h1><br/>
MNISTデータセットを使って拡散モデルの学習と、学習したモデルを使った画像を生成をしていきます。
<p/>
これを実現するコードがすでに<br/>
<a href="https://github.com/MarceloGennari/diffusion_mnist">https://github.com/MarceloGennari/diffusion_mnist</a><br/>
で公開されていましたので、こちらを利用して試します。
<p/>
なお、拡散モデルについての説明は検索するとたくさん出てきますので理論的背景については論文や解説記事を参照ください。
本記事では具体的に何をすれば拡散モデルを動かせるのかを見ていきます。
<p/>
元論文は<a href="https://arxiv.org/abs/2006.11239">arXiv:2006.11239</a>です。
<h1 class="section">まずは動かす</h1><br/>
ソースコードを<span class="code">git clone</span>で取得します。
ここでは、コミットハッシュが<span class="code">df15ee746a</span>のものを使用します。
README.mdを読んで、必要なモジュールをpipでインストールしておきます。
<p/>
この時点では学習も生成もCPUで実行するように設定されているため、GPUで処理するように変更した後に実行します。
<h2 class="section">学習</h2><br/>
学習は<span class="code">main.py</span>で実行できるのですが、この中の
<pre class="code">
device = "cpu"
</pre>
と書かれている行を
<pre class="code">
device = "cuda"
</pre>
に書き換えます。そして
<pre class="code">
$ python main.py
</pre>
を実行すると、学習が始まります。しばらく待っていると完了し、モデルのパラメータが<span class="code">unet_mnist.pth</span>に記録されます。
<p/>
<h2 class="section">生成</h2><br/>
こちらもGPUで動くように変更します。また、学習はConditionalUNetで行われるものの生成はUNetになっているため、その点も修正します。
<p/>
修正するコードは<span class="code">inference_unet.py</span>です。
先ほどと同じように
<pre class="code">
- device = "cpu"
+ device = "cuda"
</pre>
に書き換えます。-が書き換え対象の行で、+が書き換えたあとの行の内容です。さらに、
<pre class="code">
- from models import UNet
+ from models import UNet, ConditionalUNet
</pre>
と書き換え、
<pre class="code">
- model = UNet().to(device)
+ model = ConditionalUNet().to(device)
</pre>
と書き換えます。ConditionalUNetにすると、生成時にどの数字を生成するかを指定する必要があるため、
<pre class="code">
model.eval()
+ labels = torch.randint(0, 10, (batch_size,))
+ print(labels)
+ labels_cpu = labels
+ labels = labels.to(device)
with torch.no_grad():
for t in trange(999, -1, -1):
time = torch.ones(batch_size) * t
- et = model(xt.to(device), time.to(device)) # predict noise
+ et = model(xt.to(device), time.to(device), labels) # predict noise
xt = process.inverse(xt, et.cpu(), t)
</pre>
のように、書き換えます。ランダムに0〜9の値をラベルとして指定するようにしています。
<p/>
出力部分を少し書き換えて
<pre class="code">
labels = ["Generated Images"] * 9
-
- for i in range(9):
- plt.subplot(3, 3, i + 1)
- plt.tight_layout()
- plt.imshow(xt[i][0], cmap="gray", interpolation="none")
- plt.title(labels[i])
- plt.show()
+ if t % 10 == 0:
+ plt.figure(figsize=(10, 10))
+ for i in range(25):
+ plt.subplot(5, 5, i + 1)
+ plt.tight_layout()
+ plt.imshow(xt[i][0], cmap="gray", interpolation="none")
+ plt.title(f"{labels_cpu[i]}")
+ plt.savefig(f"images/generated_t{t}.png")
+ #plt.show()
</pre>
とすると、逆拡散過程によって少しずつ数字が画像として浮かび上がるところを見ることができます。
ただし、このようにすると、生成した数字のpyplotでの描画処理のために生成時間が延びます。GPU使用率もあきらかに低下します。
途中結果を見る必要がなければ最初のコードのほうが良いでしょう。
<p/>
<h2 class="section">生成結果</h2><br/>
結果は次のようになります。ただし、乱数がいろいろなところで使われており、シードも固定されていないので、毎回結果は異なります。
<p/>
<div class="separator" style="clear: both;">
[t=990] ノイズだらけで何も読み取れません。
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQs6b8QuK7T9orRP8LB8d5Pi5Ywgiub5SGMQ2V5qavLqfm8uBPGvaSHFElHShJ8lmvle7HBsDXMPSP4rMhuiKhI_-WZ_QGJPr8J2gVqP8qqjDdrim-0z1lvrkfi0lPlNHlQxuJGY4SzSICtxLaTpcvvJoszm0bQ3h1pO_GkjG0hzM_SrgcNJ0FBw/s600/generated_t990.png" style="display: block; padding: 0em 0; text-align: left; ">
<img alt="" border="0" width="400" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQs6b8QuK7T9orRP8LB8d5Pi5Ywgiub5SGMQ2V5qavLqfm8uBPGvaSHFElHShJ8lmvle7HBsDXMPSP4rMhuiKhI_-WZ_QGJPr8J2gVqP8qqjDdrim-0z1lvrkfi0lPlNHlQxuJGY4SzSICtxLaTpcvvJoszm0bQ3h1pO_GkjG0hzM_SrgcNJ0FBw/s400/generated_t990.png"/>
</a>
</div>
<p/>
<div class="separator" style="clear: both;">
[t=700] そこはかとなく数字があるように見えるような見えないような。
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwxfyOUK67gdSXYxcwNVPdsb4aAOErS08O4nEl6FOjtXeChsYHrNlxQycXHojJagmylxDPNMFHfNJZwj2RNQ7FxFd7LhBnilbhxXFo5_Rne9RzMSXUkFwS4hAJibuwojmMG9HMb3JAzoh6ushCZptj8ONhwhLrEy9VuqQefl3LNT3ZRu2nAEi_4w/s600/generated_t700.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="400" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwxfyOUK67gdSXYxcwNVPdsb4aAOErS08O4nEl6FOjtXeChsYHrNlxQycXHojJagmylxDPNMFHfNJZwj2RNQ7FxFd7LhBnilbhxXFo5_Rne9RzMSXUkFwS4hAJibuwojmMG9HMb3JAzoh6ushCZptj8ONhwhLrEy9VuqQefl3LNT3ZRu2nAEi_4w/s400/generated_t700.png"/></a></div>
<p/>
<div class="separator" style="clear: both;">
[t=500] 遠くからみれば(ぼかしてみれば)、数字が簡単に読み取れます。
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjW19FPuDkJLU-qfSIN2LMT811xMfa1weGqcEmJcK7PiNlSFy9eaw0LAkgm6YV23Q3bVN8H_wOpJWuM7eu5sK4KIwt4XA2QJnk3lB4wBTXjqKlff0EHCrpgHf846fKiZ7I05D4xDj_oHK1Dm2_-omCwS7F7sVRkD_e6EKHo4VWFSzToqfX_VL8mQ/s600/generated_t500.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="400" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjW19FPuDkJLU-qfSIN2LMT811xMfa1weGqcEmJcK7PiNlSFy9eaw0LAkgm6YV23Q3bVN8H_wOpJWuM7eu5sK4KIwt4XA2QJnk3lB4wBTXjqKlff0EHCrpgHf846fKiZ7I05D4xDj_oHK1Dm2_-omCwS7F7sVRkD_e6EKHo4VWFSzToqfX_VL8mQ/s400/generated_t500.png"/></a></div>
<p/>
<div class="separator" style="clear: both;">
[t=300] ざらざらしていますが、十分に読めるようになりました。
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgiTlxZsfDq0B5gZ9I-sD_auq_Wro8Z1CC7QgyuzYVCwPhUlIAORZ9xjudQ_fByDoyHz9saOa-u_Pgsf68v9XUrnA0qfIAtl0QGymiV5RouVbBO_2BSnTGL5-_vrTsITVMHHPFj6AGvSx99hPeIGcb9PrPPucTB13ZeVMF9BFe7acJ7KgQUoZJrQ/s600/generated_t300.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="400" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgiTlxZsfDq0B5gZ9I-sD_auq_Wro8Z1CC7QgyuzYVCwPhUlIAORZ9xjudQ_fByDoyHz9saOa-u_Pgsf68v9XUrnA0qfIAtl0QGymiV5RouVbBO_2BSnTGL5-_vrTsITVMHHPFj6AGvSx99hPeIGcb9PrPPucTB13ZeVMF9BFe7acJ7KgQUoZJrQ/s400/generated_t300.png"/></a></div>
<p/>
<div class="separator" style="clear: both;">
[t=0] 完全にノイズが取り除かれました。アンチエイリアスは残ったままです。
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhONqm6oMxuwvSuNSQcD845pZcLAnb_RxR7RtERQAXD62Kr1S5i80jP9TUDtEezuVf1EN1YYu9MVhcduDdjBjqUhyphenhyphenidkAtU6ZBpFLDFLtto52yCpYVKICbLx6uVIbJ6iQCg1IDc1cQsdy04jNVT315ZOXFr43BLLpY96e36kPhmpOJ-Slf4tveKjw/s600/generated_t0.png" style="display: block; padding: 0em 0; text-align: left; "><img alt="" border="0" width="400" data-original-height="600" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhONqm6oMxuwvSuNSQcD845pZcLAnb_RxR7RtERQAXD62Kr1S5i80jP9TUDtEezuVf1EN1YYu9MVhcduDdjBjqUhyphenhyphenidkAtU6ZBpFLDFLtto52yCpYVKICbLx6uVIbJ6iQCg1IDc1cQsdy04jNVT315ZOXFr43BLLpY96e36kPhmpOJ-Slf4tveKjw/s400/generated_t0.png"/></a></div>
<h1 class="section">学習時の処理</h1><br/>
学習時の処理がどのように実装されているのかを見ていきます。
<p/>
<h2 class="section">上位ループ</h2><br/>
モデルの学習をする<span class="code">main.py</span>の主要な処理である学習のループ部分を抜き出して、疑似コードとして書き換えると、
<pre class="code">
for epoch in range(100):
for image, label in 学習用画像とそのラベルの集合:
# 画像に加えるノイズの強さをランダムに選択
t = torch.randint(0, 1000, (image.shape[0],))
# 画像に加えるノイズを作成
epsilon = torch.randn(image.shape)
# tとepsilonに基づいてノイズをimageに加える
diffused_image = process.forward(image, t, epsilon)
# modelを使って加えられたノイズを予測
optimizer.zero_grad()
output = model(diffused_image, t, label)
# 予測したノイズがどれだけ正しいかを評価して、モデルの重みを更新
loss = criterion(epsilon, output) # criterion = torch.nn.MSELoss()
loss.backward()
optimizer.step()
</pre>
となります。ノイズが加えられた画像から、加えられたノイズを推定するモデルを学習しているだけです。
それ以外は通常のニューラルネットワークの学習と変わりがありません。
<p/>
そしてこれは元論文のAlgorithm 1の通りの実装です。5行目の
<blockquote>
<br/>
\( \nabla_\theta \| \bm{\epsilon} - \bm{\epsilon}_\theta ( \sqrt{\bar{\alpha_t}}\bm{x}_0 + \sqrt{1-\bar{\alpha}_t}\bm{\epsilon}, t) \|^2 \)<br/>
<br/>
</blockquote>
と見比べると、\(\bm{\epsilon}\)はコード上の<span class="code">epsilon</span>に、
\(\bm{\epsilon_{\theta}}\)はコード上の<span class="code">model</span>に、
\(\sqrt{\bar{\alpha_t}}\bm{x}_0 + \sqrt{1-\bar{\alpha}_t}\bm{\epsilon}\)は<span class="code">diffused_image</span>に相当していることが分かります。
<p/>
Algorithm 1とは異なり、<span class="code">model</span>の引数にlabelが余計についていますが、これは生成する数字が0〜9のどれであるかをニューラルネットワークに指示するための値となります。
<p/>
<h2 class="section">ノイズ付加処理</h2><br/>
上位ループ内の
<pre class="code">
diffused_image = process.forward(image, t, epsilon)
</pre>
の部分について、詳細を見ていきます。
<p/>
まず、<span class="code">diffusion_model.py</span>の<span class="code">DiffusionProcess</span>の初期化処理部分である<span class="code">__init__</span>にて\(\alpha_t\)の値が計算されています。
<p/>最初に\(\beta_t\) (コード上では<span class="code">variance_schedule</span>) を
<pre class="code">
self.variance_schedule = torch.linspace(1e-4, 0.01, steps=1000)
</pre>
のように計算しています。具体的には
<pre class="code">
self.variance_schedule = [1.0000e-04, 1.0991e-04, 1.1982e-04, ... , 0.009980, 0.009990, 0.01]
</pre>
となっています。元論文では\(\beta_1=10^4\)、\(\beta_T=0.02\)、\(T=1000\)と書かれているので\(\beta_T\)の値のみ異なっています。
<p/>
\(\alpha_t = 1-\beta_t\)であるので、
<pre class="code">
self.alpha = 1 - self.variance_schedule
</pre>
にて計算され、具体的な値は
<pre class="code">
self.alpha = [0.999900, 0.999890, 0.999880 , ... , 0.990020, 0.990010, 0.990000]
</pre>
となります。さらに、\(\bar{\alpha}_t=\prod_{s=1}^t \alpha_s\)であるので、
<pre class="code">
self.alpha_bar = torch.cumprod(self.alpha, dim=0)
</pre>
にて計算され、具体的な値は
<pre class="code">
self.alpha_bar = [0.999900, 0.999790, 0.999670, ... , 0.006430, 0.006365, 0.006302]
</pre>
となります。
<p/>
これらの値を使って、<span class="code">forward</span>にてノイズを画像に付加します。
\(\sqrt{\bar{\alpha_t}}\bm{x}_0 + \sqrt{1-\bar{\alpha}_t}\bm{\epsilon}\)が計算できれば良いので、まず\(\sqrt{1-\bar{\alpha}_t}\)を
<pre class="code">
std_dev = torch.sqrt(1 - self.alpha_bar[time_step])
</pre>
で計算します。次に\(\sqrt{\bar{\alpha_t}}\)を
<pre class="code">
mean_multiplier = torch.sqrt(self.alpha_bar[time_step])
</pre>
で計算し、最後に
<pre class="code">
diffused_images = mean_multiplier * x_0 + std_dev * noise
</pre>
のように足し合わせます。<span class="code">x_0</span>が\(\bm{x}_0\)で、<span class="code">noise</span>が\(\bm{\epsilon}\)です。
<p/>
<h2 class="section">ノイズを予測するモデル</h2><br/>
ノイズを予測するモデルには小さめのUNetが使われています。コードからグラフに書き起こすと下図のようになります。
<br/>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_neMH5lRHINxUzcT-bkMeJRcx0FHje2Ysz5Oq4aJOVNSWX2Pl80NGeg_tPjE5WSYSqi35Ml-HLfOt2Mqzr-Kq3DmMvoHVD4Mb5rh_CQrWQHnlPM4D8xhD90gk6F8lU312Nc3XBAPw908oRNZTZATMRKr8S7eAjFJFDlKKD_LIWbOqwIMraud3_Q/s1788/model.png" style="display: block; padding: 1em 0; text-align: left;"><img alt="" border="0" height="900" data-original-height="1788" data-original-width="1107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_neMH5lRHINxUzcT-bkMeJRcx0FHje2Ysz5Oq4aJOVNSWX2Pl80NGeg_tPjE5WSYSqi35Ml-HLfOt2Mqzr-Kq3DmMvoHVD4Mb5rh_CQrWQHnlPM4D8xhD90gk6F8lU312Nc3XBAPw908oRNZTZATMRKr8S7eAjFJFDlKKD_LIWbOqwIMraud3_Q/s900/model.png"/></a></div>
背景が水色のボックス内にはクラス名とインスタンス化時の引数を記載しています(画像をクリックすると拡大できます)。
<p/>
降りる方向と登る方向では条件付けの場所が異なっていますが、このあたりはおおまかであっても十分に動くのでしょう。
<p/>
以下では、Pytorchで提供されているクラス以外のものを見ていきます。
<p/>
<h3 class="section">ResConvGroupNorm</h3><br/>
このクラスは以下のような構成になっています。残差接続のある、よく見かける畳み込み演算を使ったブロックです。
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDiIvTvhfVjZFddEdXh668WOwHzy0-VzMTJh_EmEPj9VMU8WvuQvdoVRoCdJry72Awm2cD1S3Z_f68ytq49ecPF6en72u9IGZluKByjfY4wDf7ymI2A-dvhY2HX-lTMlyhPvGv1ZL_ec-03FFrf1vEnBpEgGNafZee4EagDCBz3HxxIjk9-z783A/s943/ResConvGroupNorm.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" height="500" data-original-height="943" data-original-width="399" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDiIvTvhfVjZFddEdXh668WOwHzy0-VzMTJh_EmEPj9VMU8WvuQvdoVRoCdJry72Awm2cD1S3Z_f68ytq49ecPF6en72u9IGZluKByjfY4wDf7ymI2A-dvhY2HX-lTMlyhPvGv1ZL_ec-03FFrf1vEnBpEgGNafZee4EagDCBz3HxxIjk9-z783A/s500/ResConvGroupNorm.png"/></a></div>
<p/>
<h3 class="section">LabelEmbedding</h3><br/>
このクラスは、0〜9のラベルをベクトルに変換し、入力値\(x\)に埋め込む処理をします。画像のチャネル方向に埋め込むので、各チャネルの画像特徴が埋め込みによって全体的に明るくなったり暗くなったりすることになります。
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMUY_pQPOdkclr2eDpaZ4PYhi5cHsw4FoagAgnM0hpomro_tWqB6eOf_2TLcGEPxJXUuiGnWcR8SKQJcBGW3DDFfoGgSYpX5RuwImjWPr_Fd8iQ5vlb1Orf8oeOEyATAH6glsrWCQMzAa383hMmb-aCR2ciqUhJ2sVa8LBDdTbzGKYB8GoeKmmtA/s512/LabelEmbedding.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" height="400" data-original-height="512" data-original-width="269" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMUY_pQPOdkclr2eDpaZ4PYhi5cHsw4FoagAgnM0hpomro_tWqB6eOf_2TLcGEPxJXUuiGnWcR8SKQJcBGW3DDFfoGgSYpX5RuwImjWPr_Fd8iQ5vlb1Orf8oeOEyATAH6glsrWCQMzAa383hMmb-aCR2ciqUhJ2sVa8LBDdTbzGKYB8GoeKmmtA/s400/LabelEmbedding.png"/></a></div>
<p/>
<h3 class="section">TemporalEmbedding</h3><br/>
このクラスは、加えるノイズの強さを表す時刻\(t\)を入力値\(x\)に埋め込む処理をします。こちらも画像のチャネル方向に埋め込むので、各チャネルの画像特徴が埋め込みによって全体的に明るくなったり暗くなったりすることになります。LabelEmbeddingと干渉しそうですが、モデルの学習時にうまく棲み分けしているのでしょう。
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-BXxUvMpRCT5FFgCC4cGRSZeBWhLU-qU3dekuS6Rqep0xnh9nTOqYrOSJNMORh4Q968gN1xMdqLWS0Jx0KLT5glUO42Sry1FTTPRR1F5Oinix4yBZHSgXV3vu9zJuNKHZNakVA8UkAYiF1If5l2cGnZt94VOP8_i_KZT-9ldxGRYGBAlx3mXTCw/s491/TemporalEmbedding.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="400" data-original-height="489" data-original-width="491" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-BXxUvMpRCT5FFgCC4cGRSZeBWhLU-qU3dekuS6Rqep0xnh9nTOqYrOSJNMORh4Q968gN1xMdqLWS0Jx0KLT5glUO42Sry1FTTPRR1F5Oinix4yBZHSgXV3vu9zJuNKHZNakVA8UkAYiF1If5l2cGnZt94VOP8_i_KZT-9ldxGRYGBAlx3mXTCw/s400/TemporalEmbedding.png"/></a></div>
SinusoidalPositionEmbeddingsは<a href="https://browse.arxiv.org/pdf/1706.03762.pdf">arXiv:1706.03762</a>の
\[ PE_{(pos,2i)} = sin(pos/10000^{2i/d_{model}}) \]
\[ PE_{(pos,2i+1)} = cos(pos/10000^{2i/d_{model}}) \]
とほぼ同じ計算をしています。\(sin\)と\(cos\)の引数部分のみ取り出すと、
\[ pos/10000^{2i/d_{model}} \]
となり、\(pos\)を時刻\(t\)、\(d_{model}\)を単に\(d\)と書き換えると、
\[ t/10000^{2i/d} \]
となります。iは次元方向のインデックスです。もう少し書き換えて、
\[ t/10000^{i/(d/2)} \]
\(i/(d/2)\)の範囲が[0,1]になるように、少し値は変わりますが、
\[ t/10000^{i/(d/2-1)} \]
とします。さらに、
\[
\begin{aligned}
\frac{t}{\exp\left(\log 10000^{i/(d/2-1)}\right)} &= t \cdot \exp \left(-\log 10000^{i/(d/2-1)} \right) \\
&= t \cdot \exp \left(-\frac{i}{\frac{d}{2}-1} \log 10000 \right)
\end{aligned}
\]
と変形します。ここまで変形するとコードとの対応がとれ、
<pre class="code">
half_dim = self.dim // 2
</pre>
で\(d/2\)を計算し、
<pre class="code">
embeddings = math.log(10000) / (half_dim - 1)
</pre>
で、\(\frac{1}{\frac{d}{2}-1} \log 10000\)を計算し、続いて
<pre class="code">
embeddings = torch.exp(torch.arange(half_dim, device=device) * -embeddings)
</pre>
で、\(\exp \left(-\frac{i}{\frac{d}{2}-1} \log 10000 \right)\)を計算していることが分かります。
<p/>
なお、変形前の\(1/10000^{i/(d/2-1)}\)にしたがって
<pre class="code">
1/torch.pow(10000, torch.arange(half_dim, device=device)/(half_dim-1))
</pre>
で計算しても、結果はほとんど変わりません。具体的には、最初の5つの値を出力すると、
<pre class="code">
式変形前 [1.0000000000, 0.9821373820, 0.9645937681, 0.9473634958, 0.9304410219]
式変形後 [1.0000000000, 0.9821373224, 0.9645937085, 0.9473634958, 0.9304410219]
</pre>
となるので、どちらで計算してもよさそうです。
<p/>
さて、時刻\(t\)をかけると
<pre class="code">
embeddings = time[:, None] * embeddings[None, :]
</pre>
となり、最後に、
<pre class="code">
embeddings = torch.cat((embeddings.sin(), embeddings.cos()), dim=-1)
</pre>
のように\(sin\)と\(cos\)を通し、それらを連結することで、埋め込みベクトルが作成できます。
<p/>
<h3 class="section">LinearAttention</h3><br/>
attention1のクラスであるLinearAttentionの実装のアイデアの元と思われる論文は
<ul>
<li><a href="https://arxiv.org/abs/1812.01243">arXiv:1812.01243</a></li>
<li><a href="https://arxiv.org/abs/2007.14902">arXiv:2007.14902</a></li>
</ul>
のあたりのようですが、ぴったり当てはまるものを見つけることはできませんでした。
<p/>
注意機構部分のみをコードから計算式に戻すと、
\[
d_{t'f'} = \frac{1}{\sqrt{32}}\frac{1}{7 \times 7} \sum_f{\frac{\exp(q_{t'f})}{\sum_{f''}{\exp(q_{t'f''})}} \sum_t{\frac{\exp(k_{tf})}{\sum_{t''}\exp(k_{t''f})} v_{tf'}}}
\]
となっているようです。普通の注意機構とは異なり、最初に\(K\)の特徴次元数×\(V\)の特徴次元数(今の場合は32×32)の行列を計算しているようです。
\(\frac{1}{\sqrt{32}}\)の32は\(K\)の特徴次元数で、<a href="https://arxiv.org/abs/1706.03762">arXiv:1706.03762</a>の式(1)である
\[ Attention(Q,K,V)=\mathrm{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V \]
の\(d_k\)に相当するようです。
<p/>
<h1 class="section">生成時の処理</h1><br/>
生成時の処理がどのように実装されているのかを見ていきます。
<p/>
<h2 class="section">上位ループ</h2><br/>
生成処理をしている<span class="code">inference_unet.py</span>の主要部分を疑似コードとして書き換えると、
<pre class="code">
for t in trange(999, -1, -1):
# 時刻tとラベルlabelの条件の下、ノイズを推定する
et = model(xt, t, label)
# 推定したノイズを使って画像からノイズを除去する
xt = process.inverse(xt, et, t)
# xtを画像として描画する
draw(xt)
</pre>
となります。モデルの学習時は時刻<span class="code">t</span>をランダムに選んでいましたが、
生成するときはノイズから徐々にノイズを取り除いていきます。t=999ではノイズのみ、t=0ではノイズがなくなった画像になります。
<p/>
<h2 class="section">ノイズ除去処理</h2><br/>
上位ループ内の
<pre class="code">
xt = process.inverse(xt, et, t)
</pre>
の部分について詳細を見ていきます。
<p/>
元論文<a href="https://arxiv.org/abs/2006.11239">arXiv:2006.11239</a>のAlgorithm 2の4行目の処理
\[
\bm{x}_{t-1}=\frac{1}{\sqrt{\alpha_t}}\left(\bm{x}_t-\frac{1-\alpha_t}{\sqrt{1-\bar{\alpha}_t}} \epsilon_\theta(\bm{x}_t,t)\right)+\sigma_t\bm{z}
\]
が実装されています。<span class="code">DiffusionProcess</span>の<span class="code">inverse</span>を見ていくと、
<pre class="code">
scale = 1 / torch.sqrt(self.alpha[t])
</pre>
では\(\frac{1}{\sqrt{\alpha_t}}\)の部分が計算されています。
<pre class="code">
noise_scale = (1 - self.alpha[t]) / torch.sqrt(1 - self.alpha_bar[t])
</pre>
では\(\frac{1-\alpha_t}{\sqrt{1-\bar{\alpha}_t}}\)の部分が計算されています。
<pre class="code">
std_dev = torch.sqrt(self.variance_schedule[t])
</pre>
では\(\sigma_t\)が計算されています。
<pre class="code">
z = torch.randn(xt.shape) if t > 1 else torch.Tensor([0])
</pre>
では\(\bm{z} \sim N(0,\bm{I})\)が計算されています。ガウス分布に従うノイズを作っているだけです。
<p/>
最後にすべてをつなげて
<pre class="code">
mu_t = scale * (xt - noise_scale * et)
xt = mu_t + std_dev * z # remove noise from image
</pre>
を計算することで、Algorithm 2の4行目の処理を実現しています。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-36523970952237351962023-09-24T23:27:00.000+09:002023-09-24T23:27:24.198+09:00Linuxのbootパーティションの空き容量を増やしたいLinuxで /boot パーティションのサイズが足りず、さらに容量を増やすことも難しい場合は次のようにするとカーネルイメージのディスク使用量を多少減らすことができるかもしれません。<p/>
<ol>
<li>/etc/initramfs-tools/initramfs.conf の COMPRESS の行を編集して圧縮手法をxzに変更します。</li>
<li>update-initramfs -u</li>
</ol>
<p/>
たとえば、Ubuntu20で、<br/>
<pre class="code">
initrd.img-5.15.0-43-generic
</pre>
を使っていて、上の手順を実行すると、<br/>
<pre class="code">
217,952,335 bytes
</pre>
から<br/>
<pre class="code">
155,488,300 bytes
</pre>
にまで減らすことができました。
<p/>
Ubuntu20からUbuntu22にアップグレードしようとしてbootパーティションの容量が足りなかったときは、この方法で回避ができました。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-20104428710888560132023-03-12T22:30:00.000+09:002023-03-12T22:30:21.542+09:00ChatGPTとPerplexityの比較ChatGPTとPerplexityに色々と聞いて、結果を比較してみました。
<h1 class="section">シングルクォートorダブルクォート</h1><br/>
入力した文字列は
<pre class="code">
Pythonでは"と'のどちらが推奨されていますか?またその根拠を教えてください。
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
Pythonにおいて、 " "(ダブルクォーテーション)と ' '(シングルクォーテーション)の両方が文字列を表現するために使用されます。両方のクォーテーションの種類を使用することで、文字列内にクォーテーションが含まれる場合に便利になります。
しかし、PythonにはPEP 8と呼ばれるスタイルガイドがあり、その中で文字列の表現において、ダブルクォーテーションが推奨されています。PEP 8によると、ダブルクォーテーションがシングルクォーテーションよりも優れている理由は以下の通りです。
Pythonの標準ライブラリの多くは、ダブルクォーテーションを使用しています。
文字列内にシングルクォーテーションが含まれる場合、エスケープする必要があるため、ダブルクォーテーションの方が可読性が高くなることがあります。
シングルクォーテーションは、文字列の代わりにシングルクォーテーションを使用することができるため、文法上の意味を区別するために混乱を招く可能性があります。
しかし、Pythonのコミュニティには、シングルクォーテーションを好む人もいます。この問題には、個人的な好みやスタイルガイドに従うなどの解決策がありますが、PEP 8に従ってダブルクォーテーションを使用することが一般的に推奨されています。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
Pythonでは、シングルクォーテーション(')とダブルクォーテーション(")の両方が文字列リテラルを表現するために使用されます。Pythonの公式ドキュメントによると、どちらの方法でも同じ結果が得られます[1]。
ただし、コード内で文字列を囲む引用符を一貫して使用することが推奨されています。一般的には、Pythonコミュニティではシングルクォーテーションがより一般的であると考えられています[2][3]。
これは、ダブルクォーテーションを文字列内で使用する必要性が少ないためです。また、Pep8スタイルガイドでは、シングルクォートを使用することが推奨されています[4]。
ただし、プロジェクト内で一貫性を保つことが重要です。プロジェクト内で既に採用されているスタイルに従うことが望ましいです[5]。
</pre>
ちなみに[4]のリファレンスを見に行ってもどこに書いてあるのか見つけられませんでした。
<p/>
<a href="https://pep8-ja.readthedocs.io/ja/latest/">https://pep8-ja.readthedocs.io/ja/latest/</a>
を読むと、
<pre class="code">
Python では、単一引用符 ' で囲まれた文字列と、二重引用符 " で囲まれた文字列は同じです。この PEP では、どちらを推奨するかの立場は示しません。どちらを使うかのルールを決めて、守るようにして下さい。
</pre>
ということなので、どちらかPEP8では推奨されているわけではないようです。ChatGPTとPerplexityのどちらも誤りですね。
<p/>
<h1 class="section">きのこたけのこ</h1><br/>
入力した文字列は
<pre class="code">
きのこたけのこ戦争について教えてください。
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
「きのこたけのこ戦争」とは、日本の童謡のひとつで、作詞:さとう宗幸、作曲:いずみたくによって作られた曲です。戦争を題材にした曲で、きのこ派とたけのこ派の戦いを描いています。
歌詞の冒頭には「山の手にはきのこ派 川の手にはたけのこ派」とあり、きのこ派とたけのこ派がそれぞれ勢力を持っていることが示されています。曲の進行に従い、両派の戦いが繰り広げられますが、最終的には「みんな仲良くしましょ きのこたけのこ戦争終わりました」という歌詞で、和解が成されるという内容です。
「きのこたけのこ戦争」は、子供たちに戦争を通して、相手を理解し、和解することの大切さを教えるために作られた曲で、日本の教育現場でもよく取り上げられています。</pre>
Perplexityの出力は次の通り。
<pre class="code">
「きのこたけのこ戦争」とは、日本の菓子メーカー明治製菓が販売する「きのこの山」と「たけのこの里」のどちらが美味しいかという消費者間の論争である[1][2][3][4]。この論争は1980年代から始まり、現在でもネット上で話題になっている[2]。また、明治製菓自身も「きのこたけのこ国民大調査」と称するアンケートを実施しており、その結果を公表している[5]。
</pre>
ChatGPTの出力は面白いのですが、Perpelxityのほうが欲しい情報が得られています。
<p/>
<h1 class="section">エディタどれがいいかな</h1><br/>
入力した文字列は
<pre class="code">
エディタの宗教論争について説明してください。
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
エディタの宗教論争は、プログラマーやコンピューターエンジニアの間で長年続いている、どのエディタが最も優れているかという議論です。エディタとは、プログラムやテキストファイルを編集するためのソフトウェアのことです。
エディタの宗教論争は、個人的な好みや使い慣れている環境などによって、さまざまな立場があるため、しばしば激しい議論になります。一部のプログラマーやエンジニアは、彼らが使用するエディタについて非常に情熱的であり、そのエディタが最高であると信じて疑いません。
代表的なエディタの宗教論争としては、以下のものがあります。
Vim vs Emacs: VimとEmacsは、両方とも高度な機能を備えたテキストエディタで、プログラマーやシステム管理者などの技術者に人気があります。両方のエディタには、熟練したユーザーによって開発されたカスタムコマンドがありますが、その開発手法や哲学に対する意見の違いにより、ユーザーは通常、どちらかを使用することになります。
Sublime Text vs Atom vs Visual Studio Code: Sublime Text、Atom、およびVisual Studio Codeは、プログラマーの間で最も人気のあるエディタの1つです。これらのエディタには、豊富なプラグインとカスタマイズオプションがありますが、それぞれのエディタの利点と欠点についての議論が行われています。
IDE vs エディタ: いくつかのプログラマーやエンジニアは、統合開発環境(IDE)を使用することを好む場合があります。IDEは、エディタの機能に加えて、コンパイラ、デバッガ、および他のツールを提供します。エディタを使用することを好む人は、軽量で使いやすく、シンプルなエディタを好みます。
最近では、エディタの宗教論争は、クラウドベースのエディタ(例えば、Google Docs、Office Online、CodePen)の使用に関しても続いています。これらのエディタは、ロ
</pre>
Perplexityの出力は次の通り。
<pre class="code">
エディタ戦争とは、プログラミングを行う人々の間で、どのテキストエディタが最適かというテーマについての論争です。特にハッカー文化に属する人々の間で、自分たちが愛好するエディタを宗教的狂信とも言えるほど尊敬して扱う伝統があります。この論争は、vi派とEmacs派の二大陣営によって代表されます[1][2][3]。しかし、この論争は単なるジョークや冗談であることも多く、実際には多くのエディタが存在し、それぞれに優れた機能や使い勝手があるため、個人の好みや用途に合わ
</pre>
ChatGPT、Perplexity共に出力途中でやめてしまいました。内容はどちらも正しそうです。
<p/>
<h1 class="section">Git vs Mercurial vs Sapling</h1><br/>
入力した文字列は
<pre class="code">
GitとMercurialとSaplingのProsとConsを教えてください。
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
Git、Mercurial、およびSaplingは、分散バージョン管理システムの一例です。以下に各システムのProsとConsを示します。
GitのPros:
オープンソースであり、広く使用されている
大規模なプロジェクトに最適で、高速で効率的なブランチとマージを提供
GitHubなどの人気のあるプラットフォームで広く使用されているため、ツールやサポートが豊富にあります。
GitのCons:
初心者には学習曲線が急である
履歴の変更に対する管理が難しい場合がある
MercurialのPros:
Gitに似た機能を提供するが、より使いやすいとされている
Windowsにも対応しているため、開発者にとってはより利用しやすい
MercurialのCons:
Gitほど普及していないため、サポートが少ない場合がある
ブランチとマージの処理が遅い場合がある
SaplingのPros:
GitとMercurialの長所を組み合わせたもので、Gitのブランチ戦略を使用できる
ブランチとマージの速度が非常に速く、一般的なワークフローであっても効率的に動作する
SaplingのCons:
GitやMercurialほど普及しておらず、サポートが限られている場合がある
開発者が少ないため、コミュニティの活発性が低い場合がある
総合的に、Gitは最も広く使用されており、豊富なツールとサポートがあるため、大規模なプロジェクトに最適です。一方、MercurialはGitに似た機能を提供しながらも、より使いやすいため、初心者には適しているかもしれません。SaplingはGitやMercurialよりもブランチとマージの速度が速く、高速なワークフローが必要な場合に最適です。ただし、Saplingのサポートが限られているため、現在はGitまたはMercurialを選択することが一般的です。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
Git and Mercurial are both popular version control systems, each with their own pros and cons. Git is known for its speed, flexibility, and large user community[1].
Mercurial is praised for its ease of use, scalability, and support for multiple branches[2].
Sapling is a newer source control system developed by Meta that aims to be user-friendly and scalable[3].
It removes or changes some of the behavior of Mercurial commands to make them more consistent with modern expectations[4].
While Git and Mercurial are well-established systems with large communities, Sapling is a newer option that may appeal to those looking for a more user-friendly experience[5].
</pre>
ChatGPTもPerplexityも正しそうな出力をしています。
Perpelxityは出力がなぜか英語になってしまいました。Prosとか書いたからかもしれません。
<p/>
ChatGPTの出力の「初心者には学習曲線が急である」は誤用する多数派に引きずられて誤りを出力してしまっていますね。
<p/>
<h1 class="section">歴史</h1><br/>
入力した文字列は
<pre class="code">
1980年から10年ごとに1つずつ日本で起きた大きな出来事を教えてください。
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
以下は、1980年から2010年までの日本で起こった10年ごとの大きな出来事の例です。
1980年代:バブル景気の到来
1990年代:バブル崩壊、リーマンショックの影響による失業率上昇、そして阪神・淡路大震災
2000年代:東京地下鉄サリン事件、小泉純一郎による構造改革、そしてリニア中央新幹線計画の発表
2010年代:東日本大震災、福島第一原発事故、消費税率の引き上げ、そして東京オリンピック・パラリンピックの開催準備
</pre>
Perplexityの出力は次の通り。
<pre class="code">
1980年代:
• 1989年1月7日:昭和天皇崩御、皇太子明仁が即位[1]。
1990年代:
• 1995年1月17日:阪神・淡路大震災発生[1]。
2000年代:
• 2003年3月20日:イラク戦争に自衛隊が派遣される[2]。
2010年代:
• 2011年3月11日:東北地方太平洋沖地震(東日本大震災)発生[1]。
2020年代:
• 2020年7月24日:東京オリンピック開催予定だったが、新型コロナウイルス感染症の影響で延期される[1]。
</pre>
ChatGPTとPerplexity共にしれっと嘘をついています。
<p/>
ChatGPTの出力を見てみます。まず、東京地下鉄サリン事件は<br/>
<a href="https://ja.wikipedia.org/wiki/%E5%9C%B0%E4%B8%8B%E9%89%84%E3%82%B5%E3%83%AA%E3%83%B3%E4%BA%8B%E4%BB%B6
">https://ja.wikipedia.org/wiki/%E5%9C%B0%E4%B8%8B%E9%89%84%E3%82%B5%E3%83%AA%E3%83%B3%E4%BA%8B%E4%BB%B6</a><br/>
によると、1995年(平成7年)3月20日なので、2000年代というのは嘘ですね。
<p/>
リーマンショックは2008年なので、これも嘘。
<p/>
リニア中央新幹線は<a href="https://ja.wikipedia.org/wiki/%E4%B8%AD%E5%A4%AE%E6%96%B0%E5%B9%B9%E7%B7%9A">https://ja.wikipedia.org/wiki/%E4%B8%AD%E5%A4%AE%E6%96%B0%E5%B9%B9%E7%B7%9A</a>によると、「2011年5月26日に整備計画が決定され」と書かれているので、2000年代というのも誤りのようです。
<p/>
Perplexityは日付付きで列挙してくれました。
<p/>
Perpexityが参照したのは、<br/>
[1] <a href="https://www3.nhk.or.jp/news/special/heisei/chronology/">https://www3.nhk.or.jp/news/special/heisei/chronology/</a><br/>
[2] <a href="https://www.shugiin.go.jp/internet/itdb_kenpou.nsf/html/kenpou/chosa/shukenshi033.pdf/$File/shukenshi033.pdf">https://www.shugiin.go.jp/internet/itdb_kenpou.nsf/html/kenpou/chosa/shukenshi033.pdf/$File/shukenshi033.pdf</a><br/>
とのこと。
<p/>
出力結果のうち、1989年1月7日、1995年1月17日、2011年3月11日、2020年7月24日は正解。
2003年3月20日は<br/>
<a href="https://ja.wikipedia.org/wiki/%E8%87%AA%E8%A1%9B%E9%9A%8A%E3%82%A4%E3%83%A9%E3%82%AF%E6%B4%BE%E9%81%A3">https://ja.wikipedia.org/wiki/%E8%87%AA%E8%A1%9B%E9%9A%8A%E3%82%A4%E3%83%A9%E3%82%AF%E6%B4%BE%E9%81%A3</a><br/>
<a href="https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%A9%E3%82%AF%E6%88%A6%E4%BA%89">https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%A9%E3%82%AF%E6%88%A6%E4%BA%89</a><br/>
を読むと、軍事介入の開始日のようです。派遣日とごっちゃになってます。
<p/>
正しい文章のなかに一部だけ間違えた内容を含めるとかされると、結局検証に時間がかかるので、こういったことの調査には不向きなようです。
調査の取っ掛かりには使えるのかもしれません。
<p/>
<h1 class="section">いずも</h1><br/>
入力した文字列は
<pre class="code">
「いずも」はどういった船ですか?
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
「いずも」とは、日本の海上自衛隊が運用するヘリコプター搭載護衛艦の名称です。正式名称は「いずも型護衛艦」で、海上自衛隊の中でも最大級の艦種となっています。
「いずも」は、航空機の発着が可能なフライトデッキと、ヘリコプターを格納できるハンガーを備えています。また、レーダーやソナーなどの最新の艦載電子機器や、対空・対水上戦闘能力を持つ艦砲やミサイルなどの装備も備えています。
「いずも」は、平時には海上自衛隊の護衛艦として、また災害時には災害派遣艦としても活躍しています。また、アメリカ海軍との共同訓練などにも参加しています。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
「いずも」とは、海上自衛隊が保有する護衛艦の一種であり、2019年時点で海上自衛隊史上最大の自衛艦である[1][2]。
全長248m、最大幅38m、満載排水量2万6000トンであり、軽空母に相当する大きさだ[2]。
F-35Bを搭載・運用可能とする改修工事を受けており、「いずも」と「かが」の2隻で61億円かかった[3][4]。
</pre>
正しそうに見えます。
<p/>
<h1 class="section">ニューロン</h1><br/>
入力した文字列は
<pre class="code">
ニューロンのシナプスで使われているイオンの名前を列挙して
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
ニューロンのシナプスで使われているイオンの一部を以下に列挙します:
ナトリウムイオン (Na+)
カリウムイオン (K+)
カルシウムイオン (Ca2+)
塩化物イオン (Cl-)
これらのイオンは、神経細胞のシナプスを介して情報が伝達される際に重要な役割を果たします。具体的には、神経細胞の電気信号がシナプスを介して化学信号に変換され、シナプス前細胞から放出された神経伝達物質がシナプス後細胞の受容体に結合することで、これらのイオンが活動電位を誘発したり、神経伝達物質の放出を促進・阻害するなどの役割を担います。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
ニューロンのシナプスで使われているイオンの名前はカルシウムイオンです[1]。
</pre>
Perplexityは1個しか挙げられませんでした。
<p/>
<a href="https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%8A%E3%83%97%E3%82%B9">https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%8A%E3%83%97%E3%82%B9</a>
によるとナトリウムとカルシウムは正しいです。
<p/>
<a href="https://bsd.neuroinf.jp/wiki/%E3%82%AB%E3%83%AA%E3%82%A6%E3%83%A0%E3%83%81%E3%83%A3%E3%83%8D%E3%83%AB">https://bsd.neuroinf.jp/wiki/%E3%82%AB%E3%83%AA%E3%82%A6%E3%83%A0%E3%83%81%E3%83%A3%E3%83%8D%E3%83%AB</a>
によると、カリウムも正しいです。
<p/>
<a href="https://bsd.neuroinf.jp/wiki/%E6%8A%91%E5%88%B6%E6%80%A7%E3%82%B7%E3%83%8A%E3%83%97%E3%82%B9">https://bsd.neuroinf.jp/wiki/%E6%8A%91%E5%88%B6%E6%80%A7%E3%82%B7%E3%83%8A%E3%83%97%E3%82%B9</a>
によると、塩化物イオンも正しそうです。
<p/>
今回は嘘はなかったようです。
<p>
<h1 class="section">かな漢字変換</h1><br/>
入力した文字列は
<pre class="code">
"kyoutonokyounokyounawodonaishiharu"を漢字かな交じり文に変換して
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
今日という日は誰にしはる、と書いて「きょうとなぁをどないしはる」と読みます。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
「きょうとの きょうな きょうを どないしはる」と書くことができます。
</pre>
google IMEで変換すると<br/>
・1位候補「京都の京の京菜をどないしはる」<br/>
・2位候補「京都の今日の京菜をどないしはる」<br/>
が候補にでてくるので、そのままではIME代わりとしてはどちらも使えそうになさそうです。
<p/>
ChatGPTに関して、もうすこし試してみました。Q:が入力で、A:が回答です。A:の後ろのカッコ書きの部分は著者のコメントです。
<pre class="code">
Q:
あなたはIMEです。これから入力するローマ字は日本語を表しています。最も尤もらしい漢字かな交じり文に変換してください。
A:
はい、承知しました。以下は入力されたローマ字を漢字かな交じり文に変換したものです。
あなた → あなた or 貴方
IME → IME or 入力システム
ろうまじ → ローマ字
にほんご → 日本語
もじ → 文字
かな → 仮名
こうじょう → 交じり文
に → 「に」は漢字で表記されず、仮名で表記されます。
へんかん → 変換
して → して
Q:
kyotonokyonokyonawodonaishiharu
A: (京都の今日の京菜をどないしはる、を想定しましたが入力が誤っています。kyotoではなくkyoutoでした)
ご入力いただきありがとうございます。
「きょとのきょのきょなわをどないしはる」であれば、次のように漢字かな交じり文に変換されます。
「京都の京の恋の恋縄を如何(いか)しはる」
意味:「京都と京都で恋をしている恋人同士の絆をどうされますか?」
Q:
dai23dainaikakusouridaijin
A: (第23代内閣総理大臣、を想定)
ご入力いただきありがとうございます。
「だい23だいないかくそうりだいじん」であれば、次のように漢字かな交じり文に変換されます。
「第23代内閣総理大臣」
意味:「日本の政治において、23番目の内閣総理大臣」
Q:
qawsedrftgyhujikolp
A: (変換できないことを想定)
入力された文字列「qawsedrftgyhujikolp」は、キーボードの上から左から6文字目の「q」から始まっており、左から10文字目の「k」で方向を変え、左から5文字目の「r」でまた方向転換しています。そのため、意味のある単語や文にはなっていません。
Q:
osakakarakyotomadenokyoriwonanbaishitaraosakakaratokyomadenokyorininarimasuka
A: (正しく出力されました)
「大阪から京都までの距離を何倍したら、大阪から東京までの距離になりますか?」という意味ですね。
答えは、直線距離で約2.5倍程度になりますが、実際の移動距離は異なる場合があります。また、交通手段やルートによっても異なります。
Q:
gottuumaitakoyakinomiseoshietekureyanyaroka
A: (ごっつうまいたこやきの店教えてくれやんやろか、を想定。1文字間違い)
ご入力いただきありがとうございます。
「ごっつうまいたこ焼きの店教えてくれやんなろか?」であれば、次のように解釈できます。
「とても美味しいたこ焼きを売っているお店を教えていただけませんか?」
「ごっつうまい」は「とても美味しい」を強調した方言表現です。また、「くれやんなろか?」は方言で、「くださいよね?」という意味になります。
Q:
yoruniasageba mane
A: (夜にあさげばまね、を想定。まね、が誤って変換されました。解説は間違い。「夜に歩いたら駄目だ」なら正解)
ご入力いただきありがとうございます。
「夜にあさげば真寝」という文言であれば、そのままの意味で「夜遅くに寝ると、本当に寝てしまう」という意味になります。
ただし、文脈によっては異なる解釈があるかもしれません。
Q:
ototoiyasumiyattakedo,dogenshitato
A: (一昨日休みやったけど、どげんしたと、を想定。解釈できなかった模様)
ご入力いただきありがとうございます。
「弟がやすみやったけど、道元師太と」であれば、文脈によっては意味が通じない可能性がありますが、文法的には正しい文です。
一般的には、次のように解釈できます。
「弟が休みだったけど、道元師太と一緒に過ごしました。」
ただし、「道元師太」という人物が誰かによってはわからない場合があるため、文脈によっては異なる解釈があるかもしれません。
Q:
wattihahanadearinsu
A: (わっちは花でありんす、を想定)
ご入力いただきありがとうございます。
「わっちは母なんであーりんす」という文言であれば、次のように解釈できます。
「わたしは母親なのであります(です)」
「わっち」は方言で「わたし」を表す表現で、「あーりんす」は方言で「です」を表す表現です。
Q:
wattiwahanadearinsu
A: (「は」を「わ」に変えたが、読み取られなかった)
ご入力いただきありがとうございます。
「わっちわ母なんであーりんす」という文言であれば、次のように解釈できます。
「わたしは母親なのであります(です)」
「わっち」は方言で「わたし」を表す表現で、「わ」が重ねられていることで親しみやすさが表現されています。「あーりんす」は方言で「です」を表す表現です。ただし、方言によっては異なる言葉遣いがあるため、文脈によっては異なる解釈があるかもしれません。
Q:
asunoasakarataihuugayattekimasu
A: (明日の朝から台風がやってきます、を想定)
ご入力いただきありがとうございます。
「明日の朝から体調がやってきます」という意味になります。
ただし、文脈によっては異なる解釈があるかもしれません。
</pre>
やはりIMEとしてはイマイチですね。
<p/>
<h1 class="section">日本の財政</h1><br/>
入力した文字列は
<pre class="code">
日本国の貸借対照表を見せて
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
申し訳ありませんが、私は見ることができません。私は人工知能のプログラムであり、物理的な場所に存在するわけではありません。また、日本国の貸借対照表にアクセスする権限もありません。
しかしながら、日本国の貸借対照表は、日本の国会図書館や経済産業省など、公的な機関のウェブサイトで入手可能です。そちらを参照してください。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
日本国には貸借対照表が存在します。財務省のウェブサイトで公表されており、誰でも閲覧することができます[1]。
また、経済産業省のウェブサイトでも貸借対照表が掲載されています[2]。
ただし、国全体のフローとストックの財務状況を把握するためには、一般企業には存在しない国特有の仮想資産なども考慮する必要があるとされています[3]。
</pre>
[1]のリンクからたどることはできました。参照URLがあるというのは検索目的では便利です。
<p/>
<h1 class="section">四国で最も高い山</h1><br/>
ChatGPTが参照したURLを出せるか試してみます。
<pre class="code">
Q:
四国で最も高い山の名前は?
A: (漢字は合っているものの読みを間違えています)
四国で最も高い山は、石鎚山(いしのぶさん)です。標高は1,982メートルです。
Q:
根拠となるWebページのURLを教えてください。
A: (出力されたURLは金峯山のページで間違い)
以下のURLが参考になります。
https://www.yamakei-online.com/yamanavi/yama.php?yama_id=230
</pre>
<p/>
<h1 class="section">キャッシュレス決済</h1><br/>
入力した文字列は
<pre class="code">
銀行振込はキャッシュレス決済にあたりますか?
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
はい、銀行振込はキャッシュレス決済の一種です。キャッシュレス決済とは、紙幣や硬貨を使用せずに電子的な手段で支払いを行うことを指します。銀行振込は、支払いのために紙幣や硬貨を使用せずに、銀行口座を介して電子的な取引を行う方法です。そのため、銀行振込はキャッシュレス決済の一つとして位置付けられます。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
銀行振込はキャッシュレス決済にあたります。キャッシュレス決済とは、現金以外で支払う決済手段のことであり、クレジットカードや銀行振込などがこれにあたる[1][2][3][4]。
日本のキャッシュレス決済比率は約20%と言われていますが、銀行口座を使った支払いを含めれば約50%まで引き上がるとも言われています[3]。
</pre>
どちらも正しそうです。
<p/>
<h1 class="section">オセロ</h1><br/>
入力した文字列は
<pre class="code">
オセロの初期配置を絵文字で描いて
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
Sure, here's a visual representation of the starting position for Othello using emojis:
⚪️⚫️⚪️⚪️⚪️⚪️⚪️⚪️
⚪️⚪️⚪️⚪️⚪️⚪️⚪️⚪️
⚪️⚪️⚪️⚪️⚪️⚪️⚪️⚪️
⚪️⚪️⚪️⚫️⚪️⚪️⚪️⚪️
⚪️⚪️⚪️⚪️⚫️⚪️⚪️⚪️
⚪️⚪️⚪️⚪️⚪️⚪️⚪️⚪️
⚪️⚪️⚪️⚪️⚪️⚪️⚪️⚪️
⚪️⚪️⚪️⚪️⚪️⚪️⚪️⚫️
</pre>
Perplexityの出力は次の通り。
<pre class="code">
セロの初期配置を絵文字で描くことができます。以下は一例です。
⚪️⚫️⚫️⚫️⚫️⚫️
⚫️⚪️⚪️⚪️⚪️⚫️
⚫️⚪️⚪️⚪️⚪️⚫️
⚫️⚪️⚪️⚪️⚪️⚫️
⚫️⚪️⚪️⚪️ ⚪ ⬜
⬜ ⬜ ⬜ ⬜ ⬜
(白石を「○」、黒石を「●」、「 」を空白、「■」を壁などに置き換えています。)
</pre>
どちらもハズレですね。白の絵文字が環境によっては見えないかもです。
<p/>
<h1 class="section">将棋の初期配置</h1><br/>
入力した文字列は
<pre class="code">
将棋の初期配置を絵文字で書いて
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
将棋の初期配置を絵文字で書くと以下のようになります:
🐴🩹🦫🥋🩸🥋🦫🩹🐴
🐺🩹🩹🩹🩹🩹🩹🩹🐺
🐗🩹🦊🥋🩸🥋🦊🩹🐗
🐦🩹🩹🩹🩹🩹🩹🩹🐦
🎖️🩹🎖️🩹🎖️🩹🎖️🩹🎖️
🩸🩹🩸🩹🩸🩹🩸🩹🩸
🐭🩹🩹🩹🩹🩹🩹🩹🐭
🐱🩹🦊🥋🩸🥋🦊🩹🐱
🐵🩹🩹🩹🩹🩹🩹🩹🐵
解説:
🐴: 先手の馬
🐺: 先手のライオン(本将棋ではライオンと呼びます)
🐗: 先手の豹
🐦: 先手の鳥
🎖️: 先手の玉将
🩸: 先手の兵
🐭: 後手のねずみ
🐱: 後手の猫
🐵: 後手の猿
🦫: 「絵文字」には将棋の駒の絵文字が存在しないため、「アナグマ」を代用しています。
🥋: 同様に「道着」を表す絵文字を使用しています。
</pre>
どうなっているのでしょうか。
<p/>
Perplexityの出力は次の通り。
<pre class="code">
将棋の初期配置は以下のように絵文字で書くことができます。
🐴🉑🉐🉑🉐🎖️🉑🉐🉑🉐
(先手:歩兵2、香車2、桂馬2、銀将1、金将1、王将1)
(後手:歩兵2、香車2、桂馬2、銀将1、金将1、王将1)
</pre>
こっちも変。絵文字というのが良くないようです。
<p/>
<h1 class="section">将棋の初期配置 その2</h1><br/>
入力した文字列は
<pre class="code">
将棋の初期配置を文字で描いて。罫線を使って枠も描いて。
</pre>
ChatGPTの出力は次の通り。
<pre class="code">
はい、以下に将棋の初期配置を文字で描き、罫線で枠を描きます。
┏━┯━┯━┯━┯━┯━┯━┯━┓
┃ │香│桂│銀│金│王│金│銀│桂│香│
┠─┼─┼─┼─┼─┼─┼─┼─┨
┃歩│歩│歩│歩│歩│歩│歩│歩│歩│
┠─┼─┼─┼─┼─┼─┼─┼─┨
┃ │ │ │ │ │ │ │ │ │
┠─┼─┼─┼─┼─┼─┼─┼─┨
┃ │ │ │ │ │ │ │ │ │
┠─┼─┼─┼─┼─┼─┼─┼─┨
┃ │ │ │ │ │ │ │ │ │
┠─┼─┼─┼─┼─┼─┼─┼─┨
┃ │ │ │ │ │ │ │ │ │
┠─┼─┼─┼─┼─┼─┼─┼─┨
┃歩│歩│歩│歩│歩│歩│歩│歩│歩│
┠─┼─┼─┼─┼─┼─┼─┼─┨
┃ │飛│角│金│ │金│ │馬│飛│
┗━┷━┷━┷━┷━┷━┷━┷━┛
※棋譜や駒落ちのルール等によっては、初期配置が異なる場合があります。
</pre>
Perplexityの出力は次の通り。
<pre class="code">
将棋の初期配置は以下のようになります。罫線を使って枠も描きました。
┏━┳━┳━┳━┳━┳━┳━┳━┓
┃香│桂│銀│金│玉│金│銀│桂│
┣━╋━╋━╋━╋━╋━╋━╋━┫
┃ │飛│ │ │ │ │角│ │
┣━╋━╋━╋━╋━╋━╋━╋━┫
┃歩│歩│歩│歩│歩│歩│歩│歩 │
┗━━━━━━━━━━━━━━─
※将棋盤は9×9マスです。
</pre>
ChatGPTはいろいろずれています。Perplexityは8x3の出力になっています。雰囲気は出ていますが、どちらも正しくないです。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-35968928716900925612023-03-06T00:10:00.003+09:002023-03-06T00:10:26.796+09:00subprocess.runの文字列長の制限Pythonのsubprocess.runで長い引数を使うと、エラーが発生して実行できません。
<p/>
そこで、手元のLinux環境で限界を調べてみました。
<p/>
最初に引数の最大値を調べてみます。
<pre class="code">
$ getconf ARG_MAX
2097152
</pre>
と表示されました。
<p/>
次に、Python経由でコマンドを実行してみます。
<pre class="code">
subprocess.run(["echo", "a"*131071])
</pre>
はエラーが発生せずに動作しました。
<p/>
一方、
<pre class="code">
subprocess.run(["echo", "a"*131072])
</pre>
だと、
<pre class="code">
<省略>
File "/usr/lib/python3.9/subprocess.py", line 505, in run
with Popen(*popenargs, **kwargs) as process:
File "/usr/lib/python3.9/subprocess.py", line 951, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/usr/lib/python3.9/subprocess.py", line 1823, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 7] Argument list too long: 'echo'
</pre>
となり、長すぎというエラーが出ました。ARG_MAXの値よりもずいぶんと短い値でエラーになります。
<p/>
複数の引数ならどうなるかを試してみます。
<pre class="code">
subprocess.run(["echo"]+["a"*131071]*15)
</pre>
はエラーが発生せずに動作しました。
runに渡した文字列長はリストの要素をスペース1個でつなげるとすると1966084バイトで、ARG_MAXを下回っています。
<p/>
一方、
<pre class="code">
subprocess.run(["echo"]+["a"*131071]*16)
</pre>
だと先程と同じエラーが発生します。
この場合の文字列の長さは2097156でARG_MAXを超えています。
<p/>
というわけで、引数の長さには2つ制限があり、
<ul>
<li>引数単位での文字列長の上限</li>
<li>コマンド全体での長さの上限</li>
</ul>
の2つがあることがわかりました。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-90293944683804770182023-01-09T22:08:00.003+09:002023-01-09T22:18:54.659+09:00Saplingを試してみるMetaで開発されているSaplingが公開されましたので、使ってみます。
<ol>
<li><a href="#install">インストール</a></li>
<li><a href="#config">初期設定</a></li>
<li><a href="#init">リポジトリの作成</a></li>
<li><a href="#add">ファイルを追加</a></li>
<li><a href="#commit">編集してコミット</a></li>
<li><a href="#log">コミットログの表示</a></li>
<li><a href="#head">headの表示</a></li>
<li><a href="#branch">分岐の作成</a></li>
<li><a href="#next">分岐で次に進む</a></li>
<li><a href="#merge">ブランチのマージ</a></li>
<li><a href="#undomerge">マージを元に戻す</a></li>
<li><a href="#rebase">rebaseにてブランチをマージ</a></li>
<li><a href="#move">コミット間の移動</a></li>
<li><a href="#undoredo">操作の取り消しと再実行</a></li>
<li><a href="#cmdlist">コマンド一覧</a></li>
</ol>
<p/>
今回はWindowsで試してみます。
<p/>
<h1 class="section" id="install">インストール</h1><br/>
インストールは、<br/>
<a href="https://github.com/facebook/sapling/releases/tag/0.2.20221222-152408-ha6a66d09">https://github.com/facebook/sapling/releases/tag/0.2.20221222-152408-ha6a66d09</a><br/>
からダウンロードしてきたzipを展開してPATHを通すだけです。
<p/>
頻繁に更新されているようなので、新規にインストールするなら最新のものを利用するのがよさそうです。
<p/>
<h1 class="section" id="config">初期設定</h1><br/>
まずは使用者名の設定をします。
<pre class="code">
$ sl config --user ui.username "yourname <yourname@mail.address.com>"
</pre>
今回は、メールアドレスを省略して、
<pre class="code">
$ sl config --user ui.username "yourname"
</pre>
としています。
<p/>
<h1 class="section" id="init">リポジトリの作成</h1><br/>
新しいリポジトリを作っていきます。<br/>
<a href="https://sapling-scm.com/docs/introduction/getting-started">https://sapling-scm.com/docs/introduction/getting-started</a><br/>
ではGithubからリポジトリを取得するように書かれていますが、ここでは実験的な機能として入っているgitのリポジトリを1から作成する方法を使ってみます。
<pre class="code">
$ sl init --git
</pre>
これは実験的な機能であるためか、<span class="code">sl help</span>でも今回試しているバージョンではコマンドが出てきません。
<p/>
何もファイルをコミットしていない状態だと、logもなにも表示されないので、<span class="code">sl show</span>を実行してみたところ、
<pre class="code">
$ sl show
changeset: 0000000000000000000000000000000000000000 (@)
user:
date: 木, 01 1 1970 09:00:00 +0900
</pre>
といった表示がされました。
<p/>
<h1 class="section" id="add">ファイルを追加</h1><br/>
お試し用のファイルを
<pre class="code">
$ echo aaa > a.txt
</pre>
のように作成します。
<p/>
次にSaplingに登録します。
<pre class="code">
$ sl add a.txt
</pre>
最後にコミットします。
<pre class="code">
$ sl commit
</pre>
Windowsでは、デフォルトではメモ帳が開くので、コミットメッセージを書いて保存し、メモ帳を終了します。
すると、コミットが完了します。
<p/>
ログを見ると、
<pre class="code">
$ sl log
changeset: 5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5 (@)
user: yourname <>
date: 木, 05 1 2023 15:31:25 +0900
summary: Initial commit
</pre>
と表示されます。
<p/>
単に<span class="code">sl</span>を実行すると、
<pre class="code">
$ sl
@ 5bbaee36d 2 minutes ago >
Initial commit
</pre>
となります。コミット時間が相対時間で表示されるので、時刻表示のほうが良い場合は<span class="code">log</span>のほうがよさそうです。
<pre class="code">
$ sl head
changeset: 5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5 (@)
user: yourname <>
date: 木, 05 1 2023 15:31:25 +0900
summary: Initial commit
</pre>
とすると、<span class="code">log</span>と同じ内容が表示されます。
<p/>
<h1 class="section" id="commit">編集してコミット</h1><br/>
次に、
<pre class="code">
$ echo "bbb" >> a.txt
</pre>
で、コミットしているファイルを編集してみます。diffをとると、
<pre class="code">
$ sl diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,1 +1,2 @@
aaa
+"bbb" <0D>
</pre>
と表示されてbbbが追加されていることがわかります。Windowsなので、改行記号が\r\nになっており、0Dが追加で表示されているようです。
<p/>
statusを表示してみると、
<pre class="code">
$ sl status
M a.txt
</pre>
となり、変更されていると表示されます。
<p/>
今回は<span class="code">sl commit -i</span>にて、対話的なコミット画面を表示してみます。
<pre class="code">
$ sl commit -i
starting interactive selection
</pre>
実行すると、
<pre class="code">
Select hunks to record - [x]=selected **=collapsed c: confirm q: abort arrow keys: move/expand/collapse space: deselect ?: help
[x] diff --git a/a.txt b/a.txt
1 hunks, 1 lines changed
[x] @@ -1,1 +1,2 @@
aaa ^M
[x] +"bbb" ^M
</pre>
と表示されます(色は省略)。Mercurialの<span class="code">hg com -i</span>や、<span class="code">git crecord</span>と同じ操作感の画面です。部分コミットを簡単にできます。
今回は1箇所しか変更していないので、そのまま<span class="code">c</span>を押して、コミットします。
<p/>
<h1 class="section" id="log">コミットログの表示</h1><br/>
単にログを表示します。
<pre class="code">
$ sl log
changeset: f4adbb569e88ed2127b9b79c0a88d22d396532aa (@)
user: yourname <>
date: 木, 05 1 2023 15:45:49 +0900
summary: Update
changeset: 5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5
user: yourname <>
date: 木, 05 1 2023 15:31:25 +0900
summary: Initial commit
</pre>
のようになり、履歴がわかります。
<p/>
<span class="code">--graph</span>にてグラフ表示もできるようです。
<pre class="code">
$ sl log --graph
@ changeset: f4adbb569e88ed2127b9b79c0a88d22d396532aa (@)
│ user: yourname <>
│ date: 木, 05 1 2023 15:45:49 +0900
│ summary: Update
│
o changeset: 5bbaee36d524dc4b97c9ee5740cf6440a37ddfb5
user: yourname <>
date: 木, 05 1 2023 15:31:25 +0900
summary: Initial commit
</pre>
単に<span class="code">sl</span>を実行すると、
<pre class="code">
$ sl
@ f4adbb569 100 seconds ago >
│ Update
│
o 5bbaee36d 16 minutes ago >
Initial commit
</pre>
と表示されます。
<p/>
<h1 class="section" id="head">headの表示</h1><br/>
headを表示してみます。分岐の先頭の一覧が表示されますが、今の時点では分岐がないので、
<pre class="code">
$ sl head
changeset: f4adbb569e88ed2127b9b79c0a88d22d396532aa (@)
user: yourname <>
date: 木, 05 1 2023 15:45:49 +0900
summary: Update
</pre>
のように1つだけ表示されます。
<p/>
prevコマンドで最初のコミットに戻ってみます。
<pre class="code">
$ sl prev
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[5bbaee] Initial commit
$ sl head
changeset: f4adbb569e88ed2127b9b79c0a88d22d396532aa
user: yourname <>
date: 木, 05 1 2023 15:45:49 +0900
summary: Update
</pre>
headは変わりません。slコマンドでは
<pre class="code">
$ sl
o f4adbb569 13 minutes ago >
│ Update
│
@ 5bbaee36d 27 minutes ago >
Initial commit
</pre>
@の場所が変化します。
<p/>
<h1 class="section" id="branch">分岐の作成</h1><br/>
最初に<span class="code">a.txt</span>に文字を追加します。
<pre class="code">
$ echo "ccc" >> a.txt
</pre>
を実行し、
<pre class="code">
$ sl commit
</pre>
にてコミットします。
<pre class="code">
$ sl head
changeset: 1cae689a8bab379edcc7e1c63c305f78d37d608a (@)
user: yourname <>
date: 木, 05 1 2023 16:00:24 +0900
summary: Add ccc
changeset: f4adbb569e88ed2127b9b79c0a88d22d396532aa
user: yourname <>
date: 木, 05 1 2023 15:45:49 +0900
summary: Update
</pre>
となり、headが複数できていることがわかります。この表示はMercurialと同様です。
<p/>
<span class="code">sl</span>を実行すると、
<pre class="code">
$ sl
@ 1cae689a8 67 seconds ago >
│ Add ccc
│
│ o f4adbb569 15 minutes ago >
├─╯ Update
│
o 5bbaee36d 30 minutes ago >
Initial commit
</pre>
となります。罫線の幅を半角表示にするときれいに位置がそろうのですが、CSSでうまく書けなかったため、ずれたままで。
<p/>
また、─╯ は2文字ですが、コマンドプロンプトウィンドウでは、重ねて表示されており、分岐した線のように見えます。
一方、WSL Terminalで当該文字列を表示すると重ならないです。
<p/>
話はそれますが、 ╯ はUnicodeで<span class="code">256F</span>、UTF-8で<span class="code">E2 95 AF</span>です。
<p/>
<h1 class="section" id="next">分岐で次に進む</h1><br/>
まず、今の状態で<span class="code">sl prev</span>を実行すると、
<pre class="code">
$ sl
o 1cae689a8 4 minutes ago >
│ Add ccc
│
│ o f4adbb569 18 minutes ago >
├─╯ Update
│
@ 5bbaee36d 33 minutes ago >
Initial commit
</pre>
となり、最初のコミットに戻ってきます。
<p/>
この位置では分岐があるのでnextを実行するとどうなるかというと、
<pre class="code">
$ sl next
commit 5bbaee36d524 has multiple children, namely:
(1) [f4adbb] Update
(2) [1cae68] Add ccc
which commit to move to [1-2/(c)ancel]?
</pre>
というメッセージが出力され、どちらに進むか選ぶようになっています。
<p/>
(1)側に進んでみると、
<pre class="code">
which commit to move to [1-2/(c)ancel]? 1
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[f4adbb] Update
</pre>
と表示され、(1)側に移動できます。
<pre class="code">
$ sl
o 1cae689a8 6 minutes ago >
│ Add ccc
│
│ @ f4adbb569 20 minutes ago >
├─╯ Update
│
o 5bbaee36d 35 minutes ago >
Initial commit
</pre>
となり、たしかに、f4adbb569 に移動できていることが確認できます。
<p/>
隣の分岐に移動するには、
<pre class="code">
$ sl goto 1cae
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
でよさそうです。
<pre class="code">
$ sl
@ 1cae689a8 9 minutes ago >
│ Add ccc
│
│ o f4adbb569 24 minutes ago >
├─╯ Update
│
o 5bbaee36d 38 minutes ago >
Initial commit
</pre>
となっており、移動できていることが確認できます。
<p/>
<h1 class="section" id="merge">ブランチのマージ</h1><br/>
さきほど作成したブランチをマージします。Saplingではマージよりrebaseを使うように設計されているようですが
(<a href="https://sapling-scm.com/docs/introduction/">https://sapling-scm.com/docs/introduction/</a>のCaveatsより)、
mergeコマンドはあるのでそれでマージしてみます。
<pre class="code">
$ sl merge
</pre>
を実行すると、kdiff3をインストールしているためか、kdiff3が立ち上がって、コンフリクトを解消するよう指示が出ます。
<p/>
手動でマージすると、
<pre class="code">
$ sl merge
merging a.txt
running merge tool kdiff3 for file a.txt
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
</pre>
と表示され、マージができました。この段階ではコミットされておらず、
<pre class="code">
$ sl
@ 1cae689a8 25 minutes ago >
│ Add ccc
│
│ @ f4adbb569 39 minutes ago >
├─╯ Update
│
o 5bbaee36d 54 minutes ago >
Initial commit
</pre>
のように表示されます。@が2箇所に表示されます。
<pre class="code">
$ sl commit
</pre>
でコミットすると、
<pre class="code">
$ sl
@ b84d24eda 15 seconds ago >
├─╯ Merge
│ │
o │ f4adbb569 41 minutes ago >
│ │ Update
│ │
│ o 1cae689a8 26 minutes ago >
├─╯ Add ccc
│
o 5bbaee36d 55 minutes ago >
Initial commit
</pre>
と表示され、めでたくマージできたことが確認できます。
<p/>
<h1 class="section" id="undomerge">マージを元に戻す</h1><br/>
rebaseが推奨であるようなので、一旦これを元に戻してみます。
<p/>
インタラクティブにできそうなので、<span class="code">-i</span>付きで実行してみましたが、
<pre class="code">
$ sl undo -i
abort: interactive ui is not supported on Windows
</pre>
となり残念ながら実行できません。<span class="code">-i</span>なしで試してみると、
<pre class="code">
$ sl undo
undone to 木 1 05 16:09:49 2023 +0900, before commit
hint[undo-uncommit-unamend]: undoing commits discards their changes.
to restore the changes to the working copy, run 'sl revert -r b84d24eda1a8 --all'
in the future, you can use 'sl uncommit' instead of 'sl undo' to keep changes
hint[hint-ack]: use 'sl hint --ack undo-uncommit-unamend' to silence these hints
$ sl
@ 1cae689a8 30 minutes ago >
│ Add ccc
│
│ o f4adbb569 44 minutes ago >
├─╯ Update
│
o 5bbaee36d 59 minutes ago >
Initial commit
</pre>
と表示され、マージ処理を元に戻せています。マージしたファイルを取得する方法もメッセージに書かれており、
消えていてもリビジョン(=コミットのハッシュ値)さえわかっていればrevertで戻せるようです。
<p/>
試して見ると、
<pre class="code">
$ sl revert -r b84d24eda1a8 --all
reverting a.txt
$ sl diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,2 +1,3 @@
aaa
+"bbb" <0D>
"ccc"
</pre>
となり、たしかにマージ処理したa.txtが戻ってきます。
<p/>
さらにundoできるか試してみると、
<pre class="code">
$ sl undo
abort: uncommitted changes
</pre>
となります。revertで戻したファイルが未コミットのファイルとなっており、この状態ではundoはできないようです。
<p/>
<h1 class="section" id="rebase">rebaseにてブランチをマージ</h1><br/>
先程はブランチのコミットを維持したままマージしましたが、今度はrebaseでマージしてみます。
枝を別の場所に継ぎ変えるということです。
<p/>
今の状態は
<pre class="code">
$ sl
@ 1cae689a8 38 minutes ago >
│ Add ccc
│
│ o f4adbb569 52 minutes ago >
├─╯ Update
│
o 5bbaee36d 67 minutes ago >
Initial commit
</pre>
となっています。ここで
<pre class="code">
$ sl rebase f4ad
abort: you must specify a destination (-d) for the rebase
$ sl rebase -r f4ad
abort: you must specify a destination (-d) for the rebase
$ sl rebase -r 1cae
abort: you must specify a destination (-d) for the rebase
$ sl rebase
abort: you must specify a destination (-d) for the rebase
</pre>
としてみると、すべてエラーとなります。
<p/>
ヘルプを見ると
<pre class="code">
sl rebase [-s REV | -b REV] [-d REV] [OPTION][-i]
</pre>
と表示されるので、エラーメッセージの通りrebase先を<span class="code">-d</span>で指定する必要があるようです。
<pre class="code">
sl rebase -r f4adbb569 -d 1cae689a8
rebasing f4adbb569e88 "Update"
merging a.txt
abort: must use on-disk merge for this rebase (hit merge conflicts in a.txt), but you have working copy changes
(commit, revert, or shelve them)
</pre>
さきほどローカルの<span class="code">a.txt</span>をマージ後のものに戻していたので、エラーとなってしまっています。
<pre class="code">
$ sl revert a.txt
</pre>
で元に戻します(マージ後のローカルの<span class="code">a.txt</span>の内容を破棄します)。
<p/>
再度rebaseしてみます。
<pre class="code">
$ sl rebase -r f4adbb569 -d 1cae689a8
rebasing f4adbb569e88 "Update"
merging a.txt
hit merge conflicts (in a.txt); switching to on-disk merge
rebasing f4adbb569e88 "Update"
merging a.txt
running merge tool kdiff3 for file a.txt
f4adbb569e88 -> f292f8d2ac45 "Update"
</pre>
今回もkdiff3が立ち上がるので、手動でマージすると、rebaseが完了します。
<pre class="code">
$ sl
o f292f8d2a 88 seconds ago >
│ Update
│
@ 1cae689a8 49 minutes ago >
│ Add ccc
│
o 5bbaee36d 78 minutes ago >
Initial commit
</pre>
となり、一直線になりました。
ヘルプを読むとrebaseしたコミットを適用先にコピーし、さらにrebaseしたブランチを隠すという処理が行われているようです。
<pre class="code">
$ sl head
changeset: f292f8d2ac45f92a9737cf4d2dd38be2e1a6fb11
user: yourname <>
date: 木, 05 1 2023 16:47:58 +0900
summary: Update
</pre>
のように、headも1つになりました。コミット履歴が読みやすいので、マージよりもコミット履歴の管理としてはこの方が良いのかもしれません。
一方で、リビジョン番号は変わってしまうので、リビジョン番号を維持しておきたい場合はmergeのほうがよいかもしれません。
rebaseでも元のコミットは隠されているだけで残ってはいますが、コピーができてしまってどれとどれが同じコミットなのかを後から追いにくくなりそうですので、リビジョン番号が重要な場合はmergeでしょうか。
状況に合わせて適切な方法を利用することになりそうです。
<p/>
<h1 class="section" id="move">コミット間の移動</h1><br/>
これまでの説明で既に使用していますが、コミット間の移動は近くのコミットであればnextとprevで移動するのが簡単です。
<pre class="code">
$ sl next
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[f292f8] Update
$ sl
@ f292f8d2a 15 minutes ago >
│ Update
│
o 1cae689a8 62 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
$ echo ddd >> a.txt
$ sl commit
$ sl
@ da3ea5b13 22 seconds ago >
│ Add ddd
│
o f292f8d2a 15 minutes ago >
│ Update
│
o 1cae689a8 63 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
$ sl prev
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[f292f8] Update
$ sl
o da3ea5b13 50 seconds ago >
│ Add ddd
│
@ f292f8d2a 16 minutes ago >
│ Update
│
o 1cae689a8 64 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
</pre>
<h1 class="section" id="undoredo">操作の取り消しと再実行</h1><br/>
なんらかの制限はあるようですが、操作の取り消し(undo)と再実行(redo)も簡単にできます。
<p/>
先程の操作を元に戻していきます。
<pre class="code">
$ sl undo
undone to 木 1 05 17:03:41 2023 +0900, before prev
$ sl
@ da3ea5b13 81 seconds ago >
│ Add ddd
│
o f292f8d2a 16 minutes ago >
│ Update
│
o 1cae689a8 64 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
</pre>
確かにprevコマンドを実行する前の状態に戻りました。さらに取り消すと、
<pre class="code">
$ sl undo
undone to 木 1 05 17:02:45 2023 +0900, before commit
$ sl
@ f292f8d2a 17 minutes ago >
│ Update
│
o 1cae689a8 65 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
</pre>
dddを追加したコミットが消えました。もう一度実行すると、
<pre class="code">
$ sl undo
undone to 木 1 05 16:48:26 2023 +0900, before next
$ sl
o f292f8d2a 18 minutes ago >
│ Update
│
@ 1cae689a8 65 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
</pre>
となり、参照している場所も戻りました。
<p/>
今度はredoで一挙にundoをundoしてみます。
<pre class="code">
$ sl redo 10
undone to 木 1 05 17:05:19 2023 +0900, before undo
$ sl
@ f292f8d2a 19 minutes ago >
│ Update
│
o 1cae689a8 67 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
</pre>
再実行はできましたが、残念ながら一括ではundo操作を戻せませんでした。
<pre class="code">
$ sl redo 2
undone to 木 1 05 17:04:52 2023 +0900, before undo
$ sl
@ da3ea5b13 5 minutes ago >
│ Add ddd
│
o f292f8d2a 21 minutes ago >
│ Update
│
o 1cae689a8 69 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
</pre>
残りのundoした回数である2を指定しても1回再実行できるだけで引数の値には効果がないようです。再度redoすると、
<pre class="code">
$ sl redo
undone to 木 1 05 17:04:19 2023 +0900, before undo
$ sl redo
abort: nothing to redo
$ sl
o da3ea5b13 6 minutes ago >
│ Add ddd
│
@ f292f8d2a 21 minutes ago >
│ Update
│
o 1cae689a8 69 minutes ago >
│ Add ccc
│
o 5bbaee36d Today at 15:31 >
Initial commit
</pre>
となり、undoする前に戻ってくることはできました。
<blockquote>
You can run 'sl redo' multiple times to undo a series of 'sl undo'
commands. Alternatively, you can explicitly specify the number of 'sl
undo' commands to undo by providing a number as a positional argument.
</blockquote>
とヘルプには書いてありましたが、できないようです。
<p/>
<h1 class="section" id="cmdlist">コマンド一覧</h1><br/>
slコマンドのヘルプ表示では表示されないコマンドを含めたコマンド一覧が<br/>
<a href="https://sapling-scm.com/docs/category/commands/">https://sapling-scm.com/docs/category/commands/</a><br/>
に載っています。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-74562244070835567942022-12-10T22:33:00.000+09:002022-12-10T22:33:23.840+09:00目玉を動かさずに視線を変えるショウジョウバエ(Drosophila)は複眼の網膜を動かすことで、体や頭を動かさずに見るところを変えられるらしい。
<p/>
<a href="https://doi.org/10.1038/s41586-022-05317-5">Fenk, L.M., Avritzer, S.C., Weisman, J.L. et al. Muscles that move the retina augment compound eye vision in Drosophila. Nature 612, 116–122 (2022).</a><br/>
<a href="https://www.natureasia.com/ja-jp/nature/highlights/118350">https://www.natureasia.com/ja-jp/nature/highlights/118350</a>
<p/>
網膜を動かす筋肉自体は1970年代に発見されていたが、今回、動きの追跡や固視微動を行っていることがわかったとのこと。<p/>
目玉は動かせないけどちょっとだけにしても視線を変えられるとは。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-14832783970171499882022-08-19T22:13:00.000+09:002023-03-06T00:10:45.294+09:00ルートにマウントする暗号化LVM領域の拡張<h1 class="section">目的</h1><br/>
Debian 10や11をインストールするとき、「ディスク全体を使い、暗号化LVMをセットアップする」ことができます。
もし、このディスクがいっぱいになってしまうと、容量を増やしたくなります。
<p/>
ここでは、ディスクを追加し、暗号化したうえで、ルートにマウントしたディスクの容量を増やしてみます。
<p/>
<b>失敗するとOSの起動ができなくなるので、元に戻せるようバックアップをとってから実行しましょう。実施する場合は自己責任で!</b>
<p/>
<h1 class="section">方法</h1><br/>
<h2 class="section">構成</h2><br/>
Physical volumeをPV1、Volume groupをVG1、Logical volumeが2つでLV-rootとLV-swapとし、構成が
<pre class="code">
[PV1]─→[VG1]┬→[LV-root]
└→[LV-swap]
</pre>
であるとき、これを
<pre class="code">
[PV1]┬→[VG1]┬→[LV-root]
[PV2]┘ └→[LV-swap]
</pre>
のように変更し、増えた容量をLV-rootに割り当てます。
PV2が新しく追加したディスクをLVMのPhysical volumeにしたものになります。
<p/>
<h2 class="section">ディスクの暗号化と起動時の暗号化解除のための手順</h2><br/>
以下、root権限で実行します。
<p/>
最初に追加したディスクを暗号化します。追加したディスクは<span class="code">/dev/sdc</span>であるとします。
<pre class="code">
$ cryptsetup --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat /dev/sdc
</pre>
実行するとパスフレーズの入力を要求されるので、設定したいパスフレーズを入力します。
<p/>
なお、暗号化アルゴリズムとキーサイズの設定は参考文献のままですので、必要に応じて変更します。
<p/>
さきほど設定したパスフレーズが正しく入力できたか確認するために、次のコマンドを実行します。
<pre class="code">
$ cryptsetup luksOpen /dev/sdc sdc_crypt
</pre>
成功したら次のステップに進みます。
<br/>
(省略してもよいかもしれませんが、もし暗号化を解除できない状態でこれ以降の作業を進めていくと今動かしているOSが起動しなくなります)
<p/>
次に、暗号化ディスクのUUIDを確認します。
<pre class="code">
cryptsetup luksDump /dev/sdc
</pre>
を実行すると、暗号化ディスクの情報が表示されます。
<pre class="code">
UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
</pre>
のxxx部分がUUIDですので、この値を<span class="code">$(UUID)</span>と書くことにします。
<p/>
UUIDがわかったので、<span class="code">/etc/crypttab</span>に次の一行を追加します。
<pre class="code">
sdc_crypt UUID=$(UUID) none luks,discard,initramfs
</pre>
行の最後に<span class="code">initramfs</span>と書いておくのがポイントです。
<p/>
編集を終えたら、
<pre class="code">
$ update-initramfs -u
</pre>
を実行して、OSの起動時の処理内容を更新します。
これにより、追加したディスクのパスフレーズによる暗号化の解除処理をOSの起動時に実施できるようになります。
<p/>
リブートして、起動時に暗号化を解除できるか確認します。
<p/>
リブートすると、これまで通り、Debianインストール時に暗号化したディスクに対するパスフレーズの入力を求められ、
続いて、今回追加したディスクのパスフレーズの入力を求められます。
<p/>
もし、パスフレーズの入力回数が増えていない(=今回追加したディスクのパスフレーズの入力が求められない)状態の場合、
なにか失敗しているので、これ以降のLVMの変更手順は実行してはいけません。OSが起動しなくなります。
<p/>
今回追加したディスクのパスフレーズの入力を求められ、暗号化を解除したうえでOSが起動すると、
<span class="code">/dev/mapper</span>にsdc_cryptが加わっているはずです。
<p/>
<h2 class="section">LVMの構成変更</h2><br/>
追加したディスクを暗号化し、それを解除できるようになったので、次はルートにマウントしているディスクの容量を増やします。
<p/>
まず、Physical volumeにsdc_cryptを追加します。
<pre class="code">
pvcreate /dev/mapper/sdc_crypt
</pre>
追加したPhysical volumeを既存のVolume group (ここではxxx-vg)に追加します。
<pre class="code">
$ vgextend xxx-vg /dev/mapper/sdc_crypt
</pre>
追加できたか確認します。
<pre class="code">
$ vgdisplay -v
</pre>
の最後のほうに、Volume groupを構成するPhysical volumeが表示されますので、それで確認ができます。
<p/>
さらに、Total PE / Free PEの行を見ると、Free PEの値がわかるので、この値を覚えておきます。
ここではこの値を<span class="code">$(Free)</span>とします。
<p/>
Logical volumeのうち、rootのvolumeの容量を増やします。
<pre class="code">
$ lvextend -l +$(Free) /dev/xxx-vg/root
</pre>
もし、$(Free)が1000なら
<pre class="code">
$ lvextend -l +1000 /dev/xxx-vg/root
</pre>
とします。
<p/>
最後に、ファイルシステムの容量を増やします。ext2またはext3、ext4であれば、
<pre class="code">
$ resize2fs /dev/xxx-vg/root
</pre>
を実行することで、ルートのディスク容量が追加したディスクの容量分だけ増えます。
他のファイルシステムを使っている場合は、適切なコマンドを実行して容量を増やします。
<p/>
これで容量が増えているはずなので、<span class="code">df</span>などでディスク容量が増えていることを確認します。
<p/>
容量が予定通り増えていれば、最後にリブートして、OSが問題なく起動するか確認します。
<p/>
正常に起動すれば、作業は完了です。
<p/>
<h1 class="section">参考文献</h1><br/>
<a href="https://qiita.com/ynakayama/items/74096212b8177234be8a">https://qiita.com/ynakayama/items/74096212b8177234be8a</a><br/>
<a href="https://blog.id774.net/entry/2014/05/13/481/">https://blog.id774.net/entry/2014/05/13/481/</a>
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-70384138233681682452022-06-05T23:31:00.000+09:002023-03-06T00:10:59.387+09:00Debian11の端末でのTERMとemacs<h1 class="section">目的</h1><br/>
Debian11をクリーンインストールした状態で、端末(gnome-terminal)の背景を黒にすると、emacsの文字が読みにくい状態になるので、視認性を上げてみます。
<p/>
3つ方法を挙げますが、方法3が最も良い方法でしょう。
<p/>
<h1 class="section">初期の状態</h1><br/>
何もしていない手元のDebian11環境では、環境変数TERMが
<pre class="code">
TERM=xterm-256color
</pre>
となっていました。
<p/>
<h1 class="section">方法1</h1><br/>
一時的にどうにかしたい場合の方法です。環境変数TERMに
<pre class="code">
TERM=screen-256color
</pre>
を設定するだけです。この方法の欠点は、一部がイタリック体になってしまうことです。
また、lessにも影響があり、文字列検索時の強調表示がイタリック体になってしまいます。
<p/>
<h1 class="section">方法2</h1><br/>
次のコマンドを実行します。
<pre class="code">
$ mkdir -p ~/.terminfo/s/
$ cp /usr/lib/terminfo/x/xterm-256color ~/.terminfo/s/screen-256color
</pre>
そして
<pre class="code">
TERM=screen-256color
</pre>
を設定します。こうすると、設定内容はxterm-256colorのままで、名前だけscreen-256colorに変更したものが参照されるようになります。
<p/>
emacsがTERMの名前でカラーテーマを決めているようで、端末の全体的な設定はもとのまま、emacsの色だけ<span class="code">TERM=screen-256color</span>と同じにできます。
<p/>
<h1 class="section">方法3</h1><br/>
素直にemacsの設定を変更します。TERMの名前に依存してカラーテーマが決まらないように変更するだけです。
<p/>
<a href="https://unix.stackexchange.com/questions/53467/emacs-colors-based-on-term-environment-variable">
https://unix.stackexchange.com/questions/53467/emacs-colors-based-on-term-environment-variable</a>
によると、emacsを起動している状態で、
<pre class="code">
M-x customize-variable [ENTER]
frame-background-mode [ENTER]
</pre>
を実行します。次のような画面が表示されるので、
<pre class="code">
For help using this buffer, see [Easy Customization] in the [Emacs manual].
[ Search ]
Operate on all settings in this buffer:
[ Revert... ] [ Apply ] [ Apply and Save ]
Hide Frame Background Mode: [Value Menu] automatic
[ State ]: SAVED and set.
The brightness of the background. Hide
Set this to the symbol ‘dark’ if your background color is dark,
‘light’ if your background is light, or nil (automatic by default)
if you want Emacs to examine the brightness for you.
If you change this without using customize, you should use
‘frame-set-background-mode’ to update existing frames;
e.g. (mapc 'frame-set-background-mode (frame-list)).
Groups: [Faces]
</pre>
[Value Menu]のところにカーソル(キャレット?)を合わせて、[ENTER]を押すと、
<pre class="code">
Available choices:
0 = dark
1 = light
2 = automatic
</pre>
のように選択肢が表示されます。今回は背景が黒であるという前提ですので、0を押します。
その後、[ Apply and Save ] にカーソルを合わせて[ENTER]を押せば、設定が保存されます。
<p/>
<h1 class="section">不思議なこと</h1><br/>
infocmpでxterm-256colorの内容を見てみると、イタリック体にするためのエスケープシーケンスが
<pre class="code">
$ infocmp xterm-256color|egrep "sitm|ritm"
rev=\E[7m, ri=\EM, rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B,
sgr0=\E(B\E[m, sitm=\E[3m, smacs=\E(0, smam=\E[?7h,
</pre>
のようにsitmとritmに設定されているにも関わらず、対応するところでは文字の色が反転してしまいます。一方、screen-256colorでは
<pre class="code">
$ infocmp screen-256color|egrep "sitm|ritm"
</pre>
のように項目が設定されていません。このscreen-256colorをTERMに使うとなぜかイタリック体になってしまいます。
<p/>
さらに、<a href="https://gist.github.com/riobard/9166725">https://gist.github.com/riobard/9166725</a>を参考に、次の内容をscreen-256color-noitalic.terminfoとして保存し(ファイル名は任意)、
<pre class="code">
screen-256color-noitalic|screen with 256 colors with no italic,
sitm=\E[7m, ritm=\E[27m,
use=screen-256color,
</pre>
次のコマンド
<pre class="code">
$ tic screen-256color-noitalic.terminfo
</pre>
を実行すると、
<pre class="code">
~/.terminfo/s/screen-256color-noitalic
</pre>
というファイルができ、TERMに設定できるようになるので、
<pre class="code">
TERM=screen-256color-noitalic emacs nanika-file
</pre>
で実行してみても、上部に表示されるemacsのメニューの文字列がイタリック体のまま変化しません。lessでも同じです。
<pre class="code">
$ infocmp screen-256color screen-256color-noitalic
comparing screen-256color to screen-256color-noitalic.
comparing booleans.
comparing numbers.
comparing strings.
ritm: NULL, '\E[27m'.
sitm: NULL, '\E[7m'.
</pre>
のように差があるにも関わらずです。不思議ですね。どこかで何か設定があり、優先されているのでしょう。
<p/>
なお、\E[3mがイタリックの開始、\E[23mがイタリックの終了、\E[7mが色反転の開始、\E[27mが色反転の終了です。
例えば、
<pre class="code">
echo -e "\E[3mitalic\E[23m \E[7mrev\E[27m"
</pre>
を端末で実行すると、イタリック体や色反転で表示されることが確認できます。bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-2561409894119826942022-05-29T14:34:00.000+09:002023-03-06T00:11:09.559+09:00Self-attentionの計算方法と行列の形状いまさらではあるものの、Self-attention (自己注意)の計算方法について途中の行列の形状に着目して調べてみました。
<p/>
結果だけ知りたい方は、最後のまとめに進んでください。
<h1 class="section">参考文献</h1><br/>
元論文は<a href="https://arxiv.org/pdf/1706.03762.pdf">Attention Is All You Need</a>です。
<p/>
論文の行間を読むか参考文献を遡っていけば、具体的にどういう計算をするのか分かるのかもしれませんが、
論文の最後に、コードへのURL
<a href="https://github.com/tensorflow/tensor2tensor">https://github.com/tensorflow/tensor2tensor</a>
が記載されていますので、こちらを主に参考にして、計算方法を調べていきます。
<h1 class="section">Q, K, Vはどうやって計算するの?</h1><br/>
論文の式(1)で使われているQ=Query、K=Key、V=Valueの3つの値の計算方法を調べてみます。
<p/>
論文のFig.1を見ると、入力が3つに分岐しているので、何かをどうにかして入力をQ, K, Vの3つにしていることはわかります。
<p/>
まず、<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/models/transformer.py#L58
">transformer_encode</a>関数を見てみます。コメントによると、入力であるinputsの形状は(batch_size, input_length, 1, hidden_dim)とのことです。
<p/>
関数の呼び出し直後に形状を変換していて、結局、inputsは(batch_size, input_length, hidden_dim)になっています。
<p/>
その後、encoder_functionが呼び出されるのですが、これの中身は、
<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/transformer_layers.py#L138">transformer_encoder</a>
です。この関数内の<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/transformer_layers.py#L213">213行目</a>から、<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L4481">common_attention.multihead_attention</a>を呼び出します。
<p/>
キャッシュがなく、self-attentionの場合であれば、<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L4650">4650行目</a>にて、<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L4423">compute_qkv</a>が呼び出されます。
ここで、Q, K, Vが計算されているようです。
<p/>
定義は
<pre class="code">
def compute_qkv(query_antecedent, ←これがcommon_kayers.layer_preprocess(x, hparams)
memory_antecedent, ←これがNone
total_key_depth,
total_value_depth,
...
</pre>
となっていて、memory_antecedentがNoneであることは、呼び出し元の<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/transformer_layers.py#L213">transformer_encoder:213</a>に戻るとわかります。
<p/>
memory_antecedentがNoneならquery_antecedentにしているので、self-attentionの場合、入力はquery_antecedentと考えればよさそうです。
<p/>
さて、Q, K, V (コード中ではq, k, v)は<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L4370">compute_attention_component</a>で計算されていて、入力は
<blockquote>
antecedent: a Tensor with shape [batch, length, channels]
</blockquote>
戻り値が
<blockquote>
c : [batch, length, depth] tensor
</blockquote>
となっています。filter_widthによって処理内容が異なるようですが、filter_width == 1のケースを見てみると、
<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L4415">4415行目</a>で
<blockquote>
<pre class="code">
return common_layers.dense(
antecedent, total_depth, use_bias=False, name=name,
layer_collection=layer_collection)
</pre>
</blockquote>
のように書かれています。バイアスなしなので、単にMatMulの計算をしているだけになります。
<p/>
<a href="https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense">Tensorflowのドキュメント</a>によると、
<blockquote>
Dense implements the operation: output = activation(dot(input, kernel) + bias) <中略> kernel is a weights matrix created by the layer,
</blockquote>
なので、
<div class="asciifigure"> depth channels depth
length [Output] = length [antecedent] × channels [W]
</div>
となります。ここで、[ ]は行列を表しています。[ ]の左が行数、[ ]の上が列数です。
<p/>
以上を考慮して<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L4423">compute_qkv</a>を読むと、q, k, vの形状は
<pre class="code">
q = (batch, length_q, total_key_depth)
k = (batch, length_kv, total_key_depth)
v = (batch, length_kv, total_value_depth)
</pre>
となっていることがわかります。
<p/>
<h1 class="section">Self-attentionの計算はどうなるの?</h1><br/>
<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L4481">multihead_attention</a>の引数に指定するattention_typeには色々種類があるようですが、デフォルト指定されているdot_productを見てみます。
<p/>
<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L1602">dot_product_attention</a>の引数の説明には、
<blockquote>
<pre class="code">
Args:
q: Tensor with shape [..., length_q, depth_k].
k: Tensor with shape [..., length_kv, depth_k]. Leading dimensions must
match with q.
v: Tensor with shape [..., length_kv, depth_v] Leading dimensions must
match with q.
</pre>
</blockquote>
と書かれています。
<p/>
まず、<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L1648">1648行目</a>で、
<blockquote>
<pre class="code">
logits = tf.matmul(q, k, transpose_b=True)
</pre>
</blockquote>
と計算しています。論文中の式(1)の\(QK^T\)の部分です。
<p/>
<div class="asciifigure"> length_kv depth_k length_kv
length_q [logits] = length_q [q] × depth_k [\({\rm k}^T\)]
</div>
のように計算されるので、logitsの形状は (..., length_q, length_kv) となります。
<p/>
式(1)の\(\sqrt{d_k}\)で割る部分が見当たりませんが、どこかで計算されているとして、次にsoftmaxの計算をみてみます。これは、<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L1654">1654行目</a>で
<blockquote>
<pre class="code">
weights = tf.nn.softmax(logits, name="attention_weights")
</pre>
</blockquote>
で計算されています。weightsの形状はlogitsと同じです。
<p/>
ドロップアウトの処理をした後、<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L1667">1667行目</a>の
<blockquote>
<pre class="code">
return tf.matmul(weights, v)
</pre>
</blockquote>
で、式(1)の計算が完了します。これは、
<div class="asciifigure"> depth_v length_kv depth_v
length_q [Attention] = length_q [weights] × length_kv [v]
</div>
を計算していますので、この関数の戻り値の形状は(..., length_q, depth_v)となります。
<p/>
<a href="https://github.com/tensorflow/tensor2tensor/blob/c8fe559e0b357389d8754474e1306b6ca9afc4f3/tensor2tensor/layers/common_attention.py#L1644">dot_product_attentionのコメント部分</a>にも
<blockquote>
<pre class="code">
Returns:
Tensor with shape [..., length_q, depth_v].
</pre>
</blockquote>
と書いてあります。
<p/>
以上の計算の途中で得られる[weights]の形状が(..., length_q, length_kv)となっており、
self-attentionの場合はlength_q=length_kvですので、系列長の2乗で必要になるメモリや計算量が増えていくことになります。
<p/>
<h1 class="section">まとめ</h1><br/>
コードを調べたことで、論文の式(1)の各行列の形状は、<br/><br/>
\(Q \in \mathbb{R}^{L_{\rm q} \times d_{\rm k}} \) <br/>
\(K \in \mathbb{R}^{L_{\rm kv} \times d_{\rm k}} \) <br/>
\(V \in \mathbb{R}^{L_{\rm kv} \times d_{\rm v}} \) <br/>
\(QK^T \in \mathbb{R}^{L_{\rm q} \times L_{\rm kv}} \) <br/>
\((QK^T)V \in \mathbb{R}^{L_{\rm q} \times d_{\rm v}} \) <br/><br/>
であることが明確になりました。ここで、\(L_{\rm q}\)は\(Q\)の系列長、\(L_{\rm kv}\)は\(K\)と\(V\)の系列長です。
\(d_{\rm k}\)と\(d_{\rm v}\)は論文と同じです。
<p/>
さらに、self-attentionの場合、\(L_{\rm q} = L_{\rm kv} \)ですので、単に\(L\)とすれば、<br/><br/>
\(Q \in \mathbb{R}^{L \times d_{\rm k}} \) <br/>
\(K \in \mathbb{R}^{L \times d_{\rm k}} \) <br/>
\(V \in \mathbb{R}^{L \times d_{\rm v}} \) <br/>
\(QK^T \in \mathbb{R}^{L \times L} \) <br/>
\((QK^T)V \in \mathbb{R}^{L \times d_{\rm v}} \) <br/><br/>
のように\(L\)の添字をなくせるのですっきりします。
<p/>
\(Q\)と\(K\)と\(V\)は、入力\(X \in \mathbb{R}^{L \times C}\)をバイアスなしのDenseレイヤーに通すことで得ることができます。
つまり、Denseレイヤーの重み行列をそれぞれ
\(W_{\rm q} \in \mathbb{R}^{C \times d_{\rm k}} \)、
\(W_{\rm k} \in \mathbb{R}^{C \times d_{\rm k}} \)、
\(W_{\rm v} \in \mathbb{R}^{C \times d_{\rm v}} \)とすると、<br/><br/>
\(Q = X W_{\rm q}\) <br/>
\(K = X W_{\rm k}\) <br/>
\(V = X W_{\rm v}\) <br/><br/>
となります。ここで、\(C\)は、\(X=\{x_1, x_2, ... ,x_i ,... x_L\}\)としたときの特徴ベクトル\(x_i\)の次元数です。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-54664868392218068282022-05-21T16:43:00.001+09:002023-03-06T00:11:24.214+09:00Raspberry Pi OSをdocker内で動かすIntel CPUの64bit環境下で、Dockerを利用してRaspberry Piの32bit OS環境を動かしてみます。
<p/>
<h1 class="section">Dockerの準備</h1><br/>
Debian11環境で作業します。
<p/>
Dockerがインストールされていなければ、例えば
<a href="https://docs.docker.com/engine/install/debian/">https://docs.docker.com/engine/install/debian/</a>
を参考にDockerをインストールします。
<h1 class="section">イメージの準備</h1><br/>
最初に、<a href="https://downloads.raspberrypi.org/">https://downloads.raspberrypi.org/</a>から必要なRaspberry Pi OSのroot.tar.xzをダウンロードします。
<p/>
Raspberry Pi OS Lite (32-bit)のバージョンbullseyeであれば、
<a href="https://downloads.raspberrypi.org/raspios_lite_armhf/archive/2022-04-07-11:57/">https://downloads.raspberrypi.org/raspios_lite_armhf/archive/2022-04-07-11:57/</a>
にあります。
<h1 class="section">Dockerのイメージへの変換</h1><br/>
次に、ダウンロードしたroot.tar.xzをDockerのイメージへと変換します。例えば、
<pre class="code">
$ docker image import ./root.tar.xz pi11-32bit:2022-04-07
</pre>
とします。インポートできたかは、
<pre class="code">
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
pi11-32bit 2022-04-07 d2b599f3a584 23 seconds ago 1.16GB
</pre>
のようにして確認できます。
<p/>
この時点では、まだ実行できません。
<pre class="code">
$ docker run -it pi11-32bit:2022-04-07 bash
exec /usr/bin/bash: exec format error
</pre>
<p/>
<p/>
(以下、方法2を実施し、その後、リブートした後に方法1を実行しましたが、もしかすると方法2の影響が残っている可能性があります)
<p/>
<h1 class="section">方法1</h1><br/>
パッケージ<span class="code">qemu-user-static</span>をホストPCにインストールするだけです。
インストールすると、
<pre class="code">
$ docker run -it --rm pi11-32bit:2022-04-07 uname -m
armv7l
</pre>
のようにエラーが起きずに実行できるようになります。
<p/>
<h1 class="section">方法2</h1><br/>
<pre class="code">
$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
</pre>
を実行します。イメージがダウンロードされて、その後、実行されます。
<p/>
実行が完了すると、ホストPC側に<span class="code">/proc/sys/fs/binfmt_misc/qemu-*</span>が作成され、
<pre class="code">
$ docker run -it pi11-32bit:2022-04-07 bash -c ls
bin boot dev etc home lib lost+found media mnt opt proc root run sbin srv sys tmp usr var
</pre>
のように動くようになります。
<p/>
なお、ホストPCをリブートすると、ホストPCで
<pre class="code">
$ ls /proc/sys/fs/binfmt_misc/
python3.9 register status
</pre>
となり、<span class="code">qemu-</span>で始まるファイルがなくなります。また、
<pre class="code">
$ docker run -it pi11-32bit:2022-04-07 bash
exec /usr/bin/bash: exec format error
</pre>
となり、実行できない状態になります。
<p/>
<h1 class="section">方法2の仕組み</h1><br/>
multiarch/qemu-user-staticコンテナ内で、ホストのbinfmt_miscとqemu-user-staticを設定することで動作させているようです。
<p/>
まず、
<a href="https://github.com/multiarch/qemu-user-static/blob/master/containers/latest/register.sh">https://github.com/multiarch/qemu-user-static/blob/master/containers/latest/register.sh</a>
を見ると
<pre class="code">
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
</pre>
と書かれており、カーネルモジュール <span class="code">binfmt_misc</span> をマウントしています(lsmodを実行するとbinfmt_miscが存在することが確認できます)。
<p/>
少なくともここでホストのルート権限が必要になり、--previlegedをつけることになります。
<p/>
また、register.shの最後に呼び出されているファイルはおそらく
<a href="https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh">https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh</a>
で、この中のqemu_register_interpreter()にて
<pre class="code">
qemu_generate_register > /proc/sys/fs/binfmt_misc/register
</pre>
という記述があることから、最終的にbinfmt_miscに対して自動的にqemuを動作させるよう登録をしています。
<p/>
<h1 class="section">参考</h1><br/>
<a href="https://www.koatech.info/blog/raspbian-on-docker/">https://www.koatech.info/blog/raspbian-on-docker/</a><br/>
<a href="https://qiita.com/autch/items/c8c9cdc7b8e5821e81a4">https://qiita.com/autch/items/c8c9cdc7b8e5821e81a4</a><br/>
<a href="https://github.com/multiarch/qemu-user-static">https://github.com/multiarch/qemu-user-static</a><br/>
<a href="https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh">https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh</a><br/>
<a href="https://wiki.bit-hive.com/north/pg/binfmt_misc">https://wiki.bit-hive.com/north/pg/binfmt_misc</a><br/>
<a href="https://qiita.com/yuyakato/items/5dd06fb179922206044d">https://qiita.com/yuyakato/items/5dd06fb179922206044d</a><br/>
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-27269927139605428082022-02-20T23:26:00.001+09:002023-03-06T00:11:37.914+09:00girgir は GObjectIntrospection Repository の略とのこと。
<p/>
DebianやUbuntuのパッケージの中に先頭に gir1.2- が付くパッケージが多数あり、このgirとは何だろうということで調べてみたところ、<br/>
<a href="https://mail.gnome.org/archives/gnome-shell-list/2011-April/msg00101.html">https://mail.gnome.org/archives/gnome-shell-list/2011-April/msg00101.html</a><br/>
に説明を見つけました。
<p/>
Introspectionの説明は<br/>
<a href="https://developer.gnome.org/documentation/guidelines/programming/introspection.html">https://developer.gnome.org/documentation/guidelines/programming/introspection.html</a><br/>
にあります。C言語のコードからAPI情報を抽出して、C言語以外の言語から呼び出せるようにする仕組みのようです。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-35525326942449480912022-02-15T00:22:00.000+09:002022-02-15T00:22:53.973+09:00Firefox 97でペンを使うWindows10環境でFirefox 97にアップデートしてペンでタブを移動させられなくなってしまった場合は、about:configから
<pre class="code">
dom.w3c_pointer_events.dispatch_by_pointer_messages
</pre>
をfalseに設定しましょう。これで、ペンでタブを移動させられるようになります。
<p/>
タッチ操作でできる画面のスクロールがペンではできなくなりますが、マウスと同様にテキストを選択できるようになるので、マウスの代わりに利用したい方にはこちらのほうが都合が良いでしょう(そもそも以前はこちらがデフォルトの動作でした)。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-57068857011412429562022-02-08T00:57:00.008+09:002022-02-09T09:42:17.602+09:00WiMAX+5Gを4Gのみで使う<h1 class="section">1行まとめ</h1></br/>
WiMAX+5GをSpeed Wi-Fi 5G X11で利用されていて、頻発する4Gと5Gの切り替えに難儀されている方は、回線がまともになるまでは「エコ」モードを使用しましょう。
<p/>
<h1 class="section">発生している現象</h1><br/>
WiMAX+5Gを利用してみました。速くていいですね。
<p/>
しかしながら、利用場所によっては落とし穴があります。
中途半端に5Gが受信できる場所では、5Gと4Gが頻繁に入れ替わる現象が発生します。
<p/>
これが理由なのかどうか明確にはわからないのですが、通信が引っかかる現象が頻発します。
ブラウザで検索したりどこかのウェブページを表示したり、ゲームで通信が発生したときなど、
全く反応がなく、結局接続できず失敗することが起きます。おそらくタイムアウトしているのでしょう。
<p/>
不思議なことに、その現象が発生しているときに別の端末で別のウェブページを開くことは普通にでき、
pingにも影響がみられませんでした。
<p/>
想像ではありますが、通信そのものは常にできているけれど、ときおりパケットが行方不明になってしまっていて、
行方不明になったパケットに依存している処理がずっと止まっているのかもしれません。
<p/>
切り替え周期を測定してみたところ、おおむね25秒〜35秒で4Gから5Gへ、または、5Gから4Gへの切り替えが発生していました。
だいたい1分でもとに戻ってくるということですね。
<p/>
アンテナが2本しか立たないところで使ってみると、4Gのみになり、切り替えは発生しないものの、
ダウンロードはともかくアップロード速度が100kbps未満というほぼ使えない状態になりました。
<p/>
<h1 class="section">他に事例は?</h1><br/>
こちらの方
<a href="https://hudetoro.com/life/2019/">https://hudetoro.com/life/2019/</a>
が同じような現象にみまわれているようです。記事を読む限り、通信を提供している側ですぐになんらかの対処が実施されることはなさそうです。
<p/>
<h1 class="section">対処方法</h1><br/>
通信が切れる問題の原因が仮に4Gと5Gとの切り替えにあるとすると、切り替えが頻発しないようにすれば安定すると思われます。
そもそも5Gを利用しなければ問題ないだろうということです。
<p/>
調べたところAndroidであれば5Gを使わない設定ができるようです。WiMAX+5Gの端末はAndroidではないので同じ方法は使えそうにありません。
<p/>
そこで、X11の取扱説明書を読んでみたところ、なんとp.64に
<pre class="code">
省電力モードが「エコ」モードを選択した場合、WAN 側回線「5G」は無効となります。
</pre>
と記載がありました(最初の「が」は「で」の誤植っぽいですが、原文ママです)。
<p/>
というわけですので、通信が切れて困っている方、X11であれば「エコ」モードにすればもしかしたら問題がましになるかもしれません。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-25914365848926017572021-12-18T23:59:00.001+09:002021-12-18T23:59:50.101+09:00zmqの通信の認証と暗号化<h1 class="section">目的</h1><br/>
ZMQで認証&通信暗号化をしてみます。言語はPythonを使います。
<p/>
<h1 class="section">コード</h1><br/>
REQ-REPで試してみます。Public keyとSecret keyを作成するコード、サーバーのコード、クライアントのコードが必要になります。
<p/>
<h2 class="section">キー作成</h2><br/>
次の<span class="code">gen_keys.py</span>を作成し、pythonで実行します。
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre class="highlight"> 1
2
3
4
5
6
7
8
9
10
11</pre></div></td><td class="code"><div class="highlight"><pre class="highlight"><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">zmq</span>
<span class="kn">import</span> <span class="nn">zmq.auth</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="s2">"cert"</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">server_public_file</span><span class="p">,</span> <span class="n">server_secret_file</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">auth</span><span class="o">.</span><span class="n">create_certificates</span><span class="p">(</span><span class="s2">"cert"</span><span class="p">,</span> <span class="s2">"server"</span><span class="p">)</span>
<span class="n">client_public_file</span><span class="p">,</span> <span class="n">client_secret_file</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">auth</span><span class="o">.</span><span class="n">create_certificates</span><span class="p">(</span><span class="s2">"cert"</span><span class="p">,</span> <span class="s2">"client"</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</td></tr></table>
すると、<span class="code">cert</span>ディレクトリに
<pre class="code">
client.key
client.key_secret
server.key
server.key_secret
</pre>
の4つのファイルが作成されます。
<p/>
<h2 class="section">サーバー</h2><br/>
サーバーのコードは以下の通り。サーバー側に認証機能をつけます。
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre class="highlight"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21</pre></div></td><td class="code"><div class="highlight"><pre class="highlight"><span></span><span class="kn">import</span> <span class="nn">zmq</span>
<span class="kn">import</span> <span class="nn">zmq.auth</span>
<span class="kn">from</span> <span class="nn">zmq.auth.thread</span> <span class="kn">import</span> <span class="n">ThreadAuthenticator</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">ctx</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Context</span><span class="o">.</span><span class="n">instance</span><span class="p">()</span>
<span class="n">auth</span> <span class="o">=</span> <span class="n">ThreadAuthenticator</span><span class="p">(</span><span class="n">ctx</span><span class="p">)</span>
<span class="n">auth</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">auth</span><span class="o">.</span><span class="n">configure_curve</span><span class="p">(</span><span class="n">location</span><span class="o">=</span><span class="s2">"cert"</span><span class="p">)</span> <span class="c1"># Need only public keys</span>
<span class="n">server</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">zmq</span><span class="o">.</span><span class="n">REP</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">curve_publickey</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">curve_secretkey</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">auth</span><span class="o">.</span><span class="n">load_certificate</span><span class="p">(</span><span class="s2">"cert/server.key_secret"</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">curve_server</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">server</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="s1">'tcp://*:9000'</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">recv_pyobj</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="s2">"server:"</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">send_pyobj</span><span class="p">(</span><span class="s2">"123"</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</td></tr></table>
無限ループをCtrl+Cで止める前提なので入れていませんが、普通は<span class="code">auth.stop()</span>で認証用スレッドを終了しましょう。
<p/>
<h2 class="section">クライアント</h2><br/>
クライアントのコードは以下の通り。サーバーのpublic keyが必要です。
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre class="highlight"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16</pre></div></td><td class="code"><div class="highlight"><pre class="highlight"><span></span><span class="kn">import</span> <span class="nn">zmq</span>
<span class="kn">import</span> <span class="nn">zmq.auth</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">ctx</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">Context</span><span class="o">.</span><span class="n">instance</span><span class="p">()</span>
<span class="n">client</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">zmq</span><span class="o">.</span><span class="n">REQ</span><span class="p">)</span>
<span class="n">client</span><span class="o">.</span><span class="n">curve_publickey</span><span class="p">,</span> <span class="n">client</span><span class="o">.</span><span class="n">curve_secretkey</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">auth</span><span class="o">.</span><span class="n">load_certificate</span><span class="p">(</span><span class="s2">"cert/client.key_secret"</span><span class="p">)</span>
<span class="n">client</span><span class="o">.</span><span class="n">curve_serverkey</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">zmq</span><span class="o">.</span><span class="n">auth</span><span class="o">.</span><span class="n">load_certificate</span><span class="p">(</span><span class="s2">"cert/server.key"</span><span class="p">)</span>
<span class="n">client</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'tcp://127.0.0.1:9000'</span><span class="p">)</span>
<span class="n">client</span><span class="o">.</span><span class="n">send_pyobj</span><span class="p">(</span><span class="s2">"abc"</span><span class="p">)</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">recv_pyobj</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="s2">"client:"</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</td></tr></table>
<p/>
サーバーを実行し、その後、クライアントを実行すると、サーバー側に
<pre class="code">
server: abc
</pre>
クライアント側に
<pre class="code">
client: 123
</pre>
と表示されます。
<p/>
クライアント側で指定するサーバーのPublic keyを間違えるとサーバーには接続できません。
また、Wiresharkで通信内容を見た限りでは、abcや123は平文では通信されていませんでした。
一方、認証関連のコード(authやcurve関連)を削除して実行すると、abcや123を平文で読むことができました。
<p/>
<h1 class="section">参考</h1><br/>
<a href="https://github.com/zeromq/pyzmq/blob/main/examples/security/generate_certificates.py">https://github.com/zeromq/pyzmq/blob/main/examples/security/generate_certificates.py</a><br/>
<a href="https://github.com/zeromq/pyzmq/blob/main/examples/security/ironhouse.py">https://github.com/zeromq/pyzmq/blob/main/examples/security/ironhouse.py</a>
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-22165406213430561202021-12-11T14:22:00.000+09:002021-12-11T14:22:44.678+09:00bashでN進数表記整数計算に限りますが、bashで<span class="code">$(( ))</span>による計算をするときに<span class="code">#</span> (ASCIIコードで0x23、シャープ、井桁、番号記号、ナンバーサイン、ハッシュ、どう呼べばよいのか?)を使うとN進数で記載できます。計算結果の表示は10進数になります。
<p/>
2進数
<pre class="code">
$ echo $((2#1110))
14
</pre>
<p/>
<p/>
3進数
<pre class="code">
$ echo $((3#201))
19
</pre>
<p/>
4進数
<pre class="code">
$ echo $((4#123))
27
</pre>
<p/>
5進数
<pre class="code">
$ echo $((5#234))
69
</pre>
<p/>
8進数
<pre class="code">
$ echo $((8#17))
15
</pre>
<p/>
10進数
<pre class="code">
$ echo $((10#17))
17
</pre>
<p/>
16進数
<pre class="code">
$ echo $((16#fe))
254
</pre>
<p/>
20進数
<pre class="code">
$ echo $((20#ji))
398
</pre>
<p/>
40進数
<pre class="code">
$ echo $((40#D))
39
</pre>
<p/>
50進数
<pre class="code">
$ echo $((50#N))
49
</pre>
<p/>
60進数
<pre class="code">
$ echo $((60#X))
59
</pre>
<p/>
64進数
<pre class="code">
$ echo $((64#Z))
61
$ echo $((64#@))
62
$ echo $((64#_))
63
</pre>
<p/>
基底の最大値は64で、それより値が大きいと
<pre class="code">
$ echo $((65#1))
bash: 65#1: 無効な基底の数値です (エラーのあるトークンは "65#1")
</pre>
とエラーになります。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-23701001954157842742021-12-07T01:46:00.000+09:002021-12-07T01:46:05.896+09:00OzoneのデータにC++でアクセスApache Ozone上にあるデータにC++でアクセスしてみます。Ozoneの準備は、「<a href="https://bluewidz.blogspot.com/2021/12/ozone.html">Ozoneを試す</a>」を参照ください。
<p/>
<h1 class="section">ライブラリのビルド</h1><br/>
<a href="https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/setup-linux.html">https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/setup-linux.html</a>を参考にビルドしていきます。
<p/>
まず、ダウンロードします。
<pre class="code">
$ git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp.git
</pre>
この日の時点では、1.4GBありました。大きいですね。
<p/>
ビルドにはUbuntuでは
libcurl4-openssl-dev, libssl-dev, uuid-dev, zlib1g-dev
をインストールしておく必要があるようです。
<p/>
ビルドします。
<pre class="code">
$ cd aws-sdk-cpp
$ mkdir sdk_build
$ cd sdk_build
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../sdk -DBUILD_ONLY="s3" ..
$ make
$ make install
</pre>
<p/>
<h1 class="section">Ozoneにアクセス</h1><br/>
<a href="https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/build-cmake.html">https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/build-cmake.html</a>などを参考に、ビルドしたライブラリを使ってOzoneにアクセスしてみます。
<p/>
すべてのBucketのすべてのObjectを読み込んで標準出力に出力するソースコード<span class="code">main.cpp</span>は次の通りです。
なお、テキストデータの表示のためヌル終端していますが、単に読み込むだけであれば不要です。
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre class="highlight"><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span>
<span class="normal">69</span>
<span class="normal">70</span>
<span class="normal">71</span>
<span class="normal">72</span>
<span class="normal">73</span>
<span class="normal">74</span>
<span class="normal">75</span>
<span class="normal">76</span></pre></div></td><td class="code"><div class="highlight"><pre class="highlight"><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf"><aws/core/Aws.h></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><aws/core/utils/logging/LogLevel.h></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><aws/s3/S3Client.h></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><aws/s3/model/ListObjectsRequest.h></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><aws/s3/model/GetObjectRequest.h></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><iostream></span><span class="cp"></span>
<span class="k">class</span> <span class="nc">Initializer</span><span class="p">{</span><span class="w"></span>
<span class="k">public</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Initializer</span><span class="p">(){</span><span class="w"></span>
<span class="w"> </span><span class="n">options</span><span class="p">.</span><span class="n">loggingOptions</span><span class="p">.</span><span class="n">logLevel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">Utils</span><span class="o">::</span><span class="n">Logging</span><span class="o">::</span><span class="n">LogLevel</span><span class="o">::</span><span class="n">Debug</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">InitAPI</span><span class="p">(</span><span class="n">options</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="o">~</span><span class="n">Initializer</span><span class="p">(){</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">ShutdownAPI</span><span class="p">(</span><span class="n">options</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="k">private</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">SDKOptions</span><span class="w"> </span><span class="n">options</span><span class="p">;</span><span class="w"></span>
<span class="p">};</span><span class="w"></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">){</span><span class="w"></span>
<span class="w"> </span><span class="n">Initializer</span><span class="w"> </span><span class="n">initializer</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">Client</span><span class="o">::</span><span class="n">ClientConfiguration</span><span class="w"> </span><span class="n">config</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="n">endpointOverride</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"http://localhost:9878"</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="c1">// client cannot access objects if useVirtualAddressing is true</span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">S3Client</span><span class="w"> </span><span class="n">client</span><span class="p">(</span><span class="n">config</span><span class="p">,</span><span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">Client</span><span class="o">::</span><span class="n">AWSAuthV4Signer</span><span class="o">::</span><span class="n">PayloadSigningPolicy</span><span class="o">::</span><span class="n">Never</span><span class="p">,</span><span class="w"> </span><span class="nb">false</span><span class="cm">/*useVirtualAddressing*/</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">ListBucketsOutcome</span><span class="w"> </span><span class="n">buckets</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">ListBuckets</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">buckets</span><span class="p">.</span><span class="n">IsSuccess</span><span class="p">()){</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Fail to get buckets"</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">ListBucketsResult</span><span class="w"> </span><span class="n">listBucketsResult</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">buckets</span><span class="p">.</span><span class="n">GetResult</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">Bucket</span><span class="w"> </span><span class="o">&</span><span class="nl">bucket</span> <span class="p">:</span><span class="w"> </span><span class="n">listBucketsResult</span><span class="p">.</span><span class="n">GetBuckets</span><span class="p">()){</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Bucket name: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">bucket</span><span class="p">.</span><span class="n">GetName</span><span class="p">()</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Get objects</span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">ListObjectsRequest</span><span class="w"> </span><span class="n">request</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">request</span><span class="p">.</span><span class="n">WithBucket</span><span class="p">(</span><span class="n">bucket</span><span class="p">.</span><span class="n">GetName</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">ListObjectsOutcome</span><span class="w"> </span><span class="n">listObjectsOutcome</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">ListObjects</span><span class="p">(</span><span class="n">request</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">listObjectsOutcome</span><span class="p">.</span><span class="n">IsSuccess</span><span class="p">()){</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Fail to get objects"</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">ListObjectsResult</span><span class="w"> </span><span class="n">listObjectsResult</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">listObjectsOutcome</span><span class="p">.</span><span class="n">GetResult</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Bucket name: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">listObjectsResult</span><span class="p">.</span><span class="n">GetName</span><span class="p">()</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Max keys: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">listObjectsResult</span><span class="p">.</span><span class="n">GetMaxKeys</span><span class="p">()</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">Vector</span><span class="o"><</span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">Object</span><span class="o">></span><span class="w"> </span><span class="o">&</span><span class="n">objects</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">listObjectsResult</span><span class="p">.</span><span class="n">GetContents</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"# of objects: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">objects</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">Object</span><span class="o">&</span><span class="w"> </span><span class="nl">object</span> <span class="p">:</span><span class="w"> </span><span class="n">objects</span><span class="p">){</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Get the attributes of the object</span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Object key: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">object</span><span class="p">.</span><span class="n">GetKey</span><span class="p">()</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">object</span><span class="p">.</span><span class="n">GetSize</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Object value size: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Get the value of the object</span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">GetObjectRequest</span><span class="w"> </span><span class="n">objectRequest</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">objectRequest</span><span class="p">.</span><span class="n">SetBucket</span><span class="p">(</span><span class="n">listObjectsResult</span><span class="p">.</span><span class="n">GetName</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="n">objectRequest</span><span class="p">.</span><span class="n">SetKey</span><span class="p">(</span><span class="n">object</span><span class="p">.</span><span class="n">GetKey</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">GetObjectOutcome</span><span class="w"> </span><span class="n">getObjectOutcome</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">GetObject</span><span class="p">(</span><span class="n">objectRequest</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">getObjectOutcome</span><span class="p">.</span><span class="n">IsSuccess</span><span class="p">()){</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Fail to get content"</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">S3</span><span class="o">::</span><span class="n">Model</span><span class="o">::</span><span class="n">GetObjectResult</span><span class="w"> </span><span class="n">getObjectResult</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">getObjectOutcome</span><span class="p">.</span><span class="n">GetResultWithOwnership</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">contentLength</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">getObjectResult</span><span class="p">.</span><span class="n">GetContentLength</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Object value size: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">contentLength</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">Aws</span><span class="o">::</span><span class="n">IOStream</span><span class="o">&</span><span class="w"> </span><span class="n">stream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">getObjectResult</span><span class="p">.</span><span class="n">GetBody</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="kt">char</span><span class="o">></span><span class="w"> </span><span class="n">buff</span><span class="p">(</span><span class="n">contentLength</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// +1 for null terminator</span>
<span class="w"> </span><span class="n">stream</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="o">&</span><span class="n">buff</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="n">buff</span><span class="p">.</span><span class="n">size</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">replace</span><span class="p">(</span><span class="n">buff</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="w"> </span><span class="n">buff</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span><span class="w"> </span><span class="sc">'\n'</span><span class="p">,</span><span class="w"> </span><span class="sc">'!'</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="s">"Object value: "</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="o">&</span><span class="n">buff</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</td></tr></table>
<span class="code">CMakeLists.txt</span>は次の通りです。
<pre class="code">
cmake_minimum_required(VERSION 3.3)
set(CMAKE_CXX_STANDARD 11)
project(s3)
add_executable(s3 main.cpp)
target_include_directories(s3 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../aws-sdk-cpp/sdk/include)
target_link_libraries(s3 ${CMAKE_CURRENT_SOURCE_DIR}/../aws-sdk-cpp/sdk/lib/libaws-cpp-sdk-s3.so
${CMAKE_CURRENT_SOURCE_DIR}/../aws-sdk-cpp/sdk/lib/libaws-cpp-sdk-core.so)
</pre>
最初に準備した<span class="code">aws-sdk-cpp</span>が、このファイルのあるディレクトリの親ディレクトリ内にあることを前提としています。
<pre class="code">
┬ aws-sdk-cpp
└ example
├CMakeLists.txt
└main.cpp
</pre>
<p/>
今、exampleディレクトリにいるとして、
<pre class="code">
$ mkdir build
$ cd build
$ cmake ..
$ make
</pre>
でビルドし、作成される<span class="code">s3</span>コマンドを実行すると、
<pre class="code">
$ ./s3
Bucket name: bucket1
Bucket name: bucket1
Max keys: 1000
# of objects: 1
Object key: test.txt
Object value size: 10
Object value size: 10
Object value: test test!
</pre>
と表示されます。正しく読み込めました。
<p/>
<h1 class="section">参考</h1><br/>
<a href="https://qiita.com/kai_kou/items/095e409539fbe77f0d59">https://qiita.com/kai_kou/items/095e409539fbe77f0d59</a>
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-86697754205678038112021-12-04T23:55:00.000+09:002021-12-04T23:55:17.776+09:00Ozoneを試すApache Ozoneを試してみます。Dockerを事前に使えるようにしておいてください。
<h1 class="section">準備</h1><br/>
Ozoneの立ち上げは
<a href="https://ozone.apache.org/docs/1.1.0/start/startfromdockerhub.html">https://ozone.apache.org/docs/1.1.0/start/startfromdockerhub.html</a>
に従って進めます。<p/>といっても、
<pre class="code">
$ docker run -p 9878:9878 -p 9876:9876 apache/ozone
</pre>
を実行するだけです。
<p/>
操作にはawsコマンドを使用しますので、Ubuntuの場合であれば、
<pre class="code">
$ apt install awscli
</pre>
インストールします。また、設定ファイルを作成する必要があるため、例えば、
<pre class="code">
$ aws configure
AWS Access Key ID [None]: default
AWS Secret Access Key [None]: default
Default region name [None]: default
Default output format [None]: text
</pre>
のようにします。今dockerで立ち上げたOzoneは
ozone.security.enabled=false
となっているため、適当な設定でもアクセスできるようです。今は試したいだけなので、このままで進めます。
<p/>
<h1 class="section">バケット作成</h1><br/>
最初にデータを保管するためのバケットを作る必要があります。バケットの説明は
<a href="https://www.ipswitch.com/jp/blog/understanding-how-aws-s3-buckets-work">https://www.ipswitch.com/jp/blog/understanding-how-aws-s3-buckets-work</a>
が参考になりました。
<p/>
以下のコマンドでbucket1という名前のバケットを作成できます。
<pre class="code">
$ aws s3api --endpoint http://localhost:9878/ create-bucket --bucket=bucket1
</pre>
<h1 class="section">オブジェクトの格納</h1><br/>
データをバケットに格納します。まずコピーするファイル test.txt を作ります。
<pre class="code">
$ echo "test test" > test.txt
</pre>
次に、このファイルをバケット内にコピーします。
<pre class="code">
$ aws s3 --endpoint http://localhost:9878 cp test.txt s3://bucket1/test.txt
upload failed: ./test.txt to s3://bucket1/test.txt An error occurred (500) when calling the PutObject operation (reached max retries: 4): Internal Server Error
</pre>
すると、エラーが発生します。今立ち上げているOzoneがシングルコンテナであるため、エラーが発生するようです。そこで、
<pre class="code">
$ aws s3 --endpoint http://localhost:9878 cp --storage-class REDUCED_REDUNDANCY test.txt s3://bucket1/test.txt
upload: ./test.txt to s3://bucket1/test.txt
</pre>
とすると成功します。
<pre class="code">
$ aws s3 --endpoint http://localhost:9878 ls s3://bucket1/test.txt
2021-12-04 22:20:53 10 test.txt
</pre>
でファイルが存在することが確認できました。また、
<pre class="code">
$ aws s3 --endpoint http://localhost:9878 cp s3://bucket1/test.txt -
test test
</pre>
でファイルの中身を表示できます。出力ファイル名を<span class="code">-</span>にすることで標準出力に流してくれるようです。
これで正しくコピーできていることが確認できました。
<p/>
<h1 class="section">Pythonから利用</h1><br/>
boto3というライブラリを用いるとPythonからアクセスできます。
<pre class="code">
$ pip3 install boto3
</pre>
でインストールします。
<p/>
次のコード
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre class="highlight"><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span></pre></div></td><td class="code"><div class="highlight"><pre class="highlight"><span></span><span class="kn">import</span> <span class="nn">boto3</span>
<span class="n">s3</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s1">'s3'</span><span class="p">,</span> <span class="n">endpoint_url</span><span class="o">=</span><span class="s2">"http://localhost:9878"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">s3</span><span class="o">.</span><span class="n">buckets</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 1:"</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 2:"</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">b</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 3:"</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 4:"</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">size</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 5:"</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">get</span><span class="p">()[</span><span class="s2">"Body"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 6:"</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">get</span><span class="p">()[</span><span class="s2">"Body"</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<span class="n">body</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">get</span><span class="p">()[</span><span class="s2">"Body"</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 7:"</span><span class="p">,</span> <span class="n">body</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 8:"</span><span class="p">,</span> <span class="n">body</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" 9:"</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">Object</span><span class="p">(</span><span class="s2">"test.txt"</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">()[</span><span class="s2">"Body"</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"10:"</span><span class="p">,</span> <span class="n">s3</span><span class="o">.</span><span class="n">Object</span><span class="p">(</span><span class="s2">"bucket1"</span><span class="p">,</span> <span class="s2">"test.txt"</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">()[</span><span class="s2">"Body"</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</pre></div>
</td></tr></table>
をpython3で実行すると、
<pre class="code">
1: s3.Bucket(name='bucket1')
2: bucket1
3: test.txt
4: 10
5: <botocore.response.StreamingBody object at 0x7f9ae2a71d00>
6: b'test test\n'
7: test test
8: b''
9: b'test test\n'
10: b'test test\n'
</pre>
という結果が出力されます。キーをリストアップしてオブジェクトの中身を表示することも、キーを指定してオブジェクトの中身を表示することもできます。
なお、取得した<span class="code">body</span>に対して2回readすると、1回目で読み終わっているため、2回目は空が返ってきます。
<p/>
<h2 class="section">参考</h2></br/>
<a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html">https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html</a><br/>
<a href="https://botocore.amazonaws.com/v1/documentation/api/latest/reference/response.html#botocore.response.StreamingBody">https://botocore.amazonaws.com/v1/documentation/api/latest/reference/response.html#botocore.response.StreamingBody</a><br/>
<a href="https://medium.com/towards-data-engineering/get-keys-inside-an-s3-bucket-at-the-subfolder-level-7be42d858372">https://medium.com/towards-data-engineering/get-keys-inside-an-s3-bucket-at-the-subfolder-level-7be42d858372</a><br/>
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-28698833535927677172021-11-27T14:01:00.001+09:002021-11-28T00:31:14.626+09:00AIのべりすと「AIのべりすと」が面白いそうなので、試してみた。<br/>
<a href="https://ai-novel.com/">https://ai-novel.com/</a>
<p/>
とりあえずデフォルト設定で以下を入れてみた。使用中の言語モデルには「とりんさま6.8B beta (2021/10/19)」と記載されていた。
<pre class="code">
吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、
</pre>
これで「続きの文を書く」を何度かクリックすると、以下のような文章が生成された。
<pre class="code">
吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうした事か? これではまるで吾輩が犬ではないか。
あああぁあああっ! なんたる不覚っ! しかし考えてみればそれも無理はないかもしれぬな。
だって吾輩は昨日人間であったのだもの。それが一晩明けて気がついたら犬になっていたのだから。
何を言っているのか解らないと思うが、吾輩も何をされたのか解らぬ。
催眠術だとか超スピードだとか、そんなチャチなものでは断じて無い。もっと恐ろしいものの片鱗を味わった気分
</pre>
ジョジョじゃないか!
<p/>
原文を探してみたところ、
<pre class="code">
な…
何を言っているのか
わからねーと思うが
おれも 何をされたのか
わからなかった…
頭がどうにかなりそうだった…
催眠術だとか超スピードだとか
そんなチャチなもんじゃあ
断じてねえ
もっと恐ろしいものの片鱗を
味わったぜ……
</pre>
であった(この部分は「ジョジョの奇妙な冒険」から引用)。一人称が変わり、口語調でなくなっているくらいの差で、ほぼ同じ。
これはモデルが大きすぎてほぼ原文を覚えてしまっている状態なのではないのだろうか?
<p/>
再現性があるか試してみたが、出力がランダムに変わるようで再現させることはできなかった。
例えば、
<pre class="code">
吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうしてこうなったのか? 事の発端は一月ほど前に遡る…… ***
「はい、これ」
学校からの帰り道、幼馴染みで親友でもある沙耶香から差し出された封筒を受け取った。表には達筆な字で『招待状』と書かれている。裏返すと
</pre>
であったり、
<pre class="code">
吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうしてこうなったのだろう? ことの始まりは1時間前に遡る――
***
「やれやれ……」
朝起きると、そこは見知らぬ部屋だった。
知らない天井だなんて古いギャグを言おうと思ったけど、本当に見覚えのない天井で少し驚いた。
俺の名前は
</pre>
といった結果が出力された。
<p/>
既存の文章に近い文章がでてくると、文章のコピペを疑われかねないので、今回のようにお試しならともかく、
自分の小説として書く場合はヒントとして使うくらいにしておいたほうが良いのかもしれない。
<p/>
ところで、さらに続きを書かせてみたら、
<pre class="code">
吾輩は猫である。名前はまだない。
そんな吾輩は今、犬になってしまった。そう、ゴールデンレトリバーに。
にゃーんと鳴いてもワンとしか声が出ない。いったい、どうした事か? これではまるで吾輩が犬ではないか。
あああぁあああっ! なんたる不覚っ! しかし考えてみればそれも無理はないかもしれぬな。
だって吾輩は昨日人間であったのだもの。それが一晩明けて気がついたら犬になっていたのだから。
何を言っているのか解らないと思うが、吾輩も何をされたのか解らぬ。
催眠術だとか超スピードだとか、そんなチャチなものでは断じて無い。もっと恐ろしいものの片鱗を味わった気分だ。
とにかく何時の間にやら、吾輩は人間ではなくなっていたらしい。
その証拠にほれこの通り、耳としっぽが付いているではないか。……ふむ、なるほど。これが俗に言う『ケモミミ』という奴か。
これはこれで悪くは無いのう。毛
</pre>
が出てきた。ジョジョシリーズになるわけではない模様。
<p/>
<p/>
[追記 2021/11/28]<br/>
ジョジョっぽい単語を入れてみた。
<pre class="code">
吾輩は猫である。名前はまだない。
そんな吾輩は今、ジョースターになってしまった。しかもエジプトに
</pre>
すると、
<pre class="code">
吾輩は猫である。名前はまだない。
そんな吾輩は今、ジョースターになってしまった。しかもエジプトに来ている。何故だか解るか? それはな――」
「まあ待てよ承太郎さんよォ~」
花京院が、何やら長くなりそうな語りを遮った。
「俺もまだ全部の事情を聞いたわけじゃあねえんだぜ。
</pre>
なんか色々間違っている気もするが、それっぽい文章がでてきた。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-46923858004992014812021-11-05T23:14:00.000+09:002021-11-05T23:14:33.112+09:00仮想マシンマネージャーでIDEディスクを選びたい<h1 class="section">目的</h1><br/>
Ubuntu 20.04 で利用できる仮想マシンマネージャー(virt-manager)でIDEのディスクを選べるようにします。
<p/>
<h1 class="section">方法</h1><br/>
新しい仮想マシンを作成するときに、チップセットをQ35ではなく、i440FXを選択します。
<p/>
<h1 class="section">詳細</h1><br/>
新しい仮想マシンを作成する際の4つあるステップの最後に「インストールの前に設定をカスタマイズする」というチェックボックスが現れるので、
チェックを入れて完了ボタンを押すと仮想マシンの設定をする画面が表示されます。
<p/>
左のリストから「概要」を選択し、右の「詳細」タブの下の方を見るとチップセットを選ぶドロップダウンリストが見つかります。
リストではQ35とi440FXが選択できます。
<p/>
Q35を選ぶとSATAやSCSI、USBコントローラは選択できるものの、IDEコントローラが選択できません。
<p/>
チップセットをi440FXにしておくと、仮想ディスクの詳細なオプションに表示されるディスクバスの選択肢に
<ul>
<li>IDE</li>
<li>SATA</li>
<li>SCSI</li>
<li>USB</li>
<li>VirtIO</li>
</ul>
が現れます。
<p/>
チップセットは仮想マシン作成後には変更できないため、作成中にi440FXを指定する必要があります。
<p/>
まっさらな状態から仮想ディスクを作成する場合にはあえてIDEを選択する必要はありませんし、
SATAのHDDからイメージを作成したときもSATAを選べば良いので使う機会は多くの人にはないでしょう。
<p/>
しかし、どうしてもIDE接続の古いHDDを仮想ディスクに変換し、仮想マシン上で動作させたいときには、IDEを選択できるチップセットi440FXが役に立つことでしょう。
<p/>
<h1 class="section">補足</h1><br/>
チップセットにQ35を指定していて、ディスクの詳細タブの右側のXMLタブを直接書き換えて、無理やりIDEを指定すると
<pre class="code">
libvirt.libvirtError: unsupported configuration: IDE controllers are unsupported for this QEMU binary or machine type
</pre>
が表示され、結局IDEは選択できません。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-80027349098556629842021-08-28T17:24:00.000+09:002021-08-28T17:24:08.320+09:00インフルエンザとか空気感染するんじゃ?インフルエンザやライノウイルスなどの呼吸器感染症の原因となるウイルスの空気感染に関して調査したレビュー論文です。<br/>
<p/>
Airborne transmission of respiratory viruses (<a href="https://doi.org/10.1126/science.abd9149">https://doi.org/10.1126/science.abd9149</a>)
<p/>
呼吸したり話をしたり咳をすることで吐き出される粒子の多くは直径1μm未満で、1μmの粒子が1.5mの高さから地面に到達するには12.2hかかるとのこと(Fig. 3)。
また、しゃべると、100μmより大きい粒子に対して100μm未満の粒子が100倍から1000倍排出されるもよう。
<p/>
粒子を吸い込むと、直径0.01μmくらいの粒子は効率よく肺胞や気管支に付着し、1μm以上の粒子は咽頭、喉頭、鼻咽腔に付着するようです(Fig. 5)。
また、なぜか0.1μm〜1μmの粒子が付着する効率は低いようです(効率が低いだけで付着しないわけではない)。
<p/>
参考までに、線香の煙の粒子径は0.2μm以下。<br/>
<a href="http://gakui.dl.itc.u-tokyo.ac.jp/cgi-bin/gazo.cgi?no=215414">http://gakui.dl.itc.u-tokyo.ac.jp/cgi-bin/gazo.cgi?no=215414</a>
<p/>
タバコの粒子サイズは0.1〜1.0μm。時間が経つと凝集しサイズが大きくなる。<br/>
<a href="https://www.sciencedirect.com/science/article/abs/pii/0095852260900374">https://www.sciencedirect.com/science/article/abs/pii/0095852260900374</a>
<a href="https://www.jstage.jst.go.jp/article/jar/1/3/1_3_156/_pdf">https://www.jstage.jst.go.jp/article/jar/1/3/1_3_156/_pdf</a>
<p/>
ということは、煙の類を効率よく排出したり空気清浄機などで集塵できるような環境を整えないと、
室内では話し手から2mくらい離れていようが、アクリル版などで衝立を立てようが、見えない煙だと思うとほぼ意味はなさそう。
<p/>
<a href="https://www.ims.u-tokyo.ac.jp/imsut/jp/about/press/page_00042.html">https://www.ims.u-tokyo.ac.jp/imsut/jp/about/press/page_00042.html</a><br/>
にあるようにマスクは効果はありそうだけれども、見えない煙相当のウイルスが充満している室内にいると、その効果も限定的になると思って行動したほうがよさそう。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-25734094023672394692021-08-01T22:24:00.002+09:002023-03-06T00:12:12.234+09:00天の川銀河の構造2012年の古い記事ですが、天の川銀河(Milky Way)がどのようになっているのか解説されている記事です。<p/>
<a href="https://www.nature.com/articles/490024a">https://www.nature.com/articles/490024a</a>
<p/>
この記事から9年の間にさらなる発見がありそうですが、どんな姿かざっと知るにはちょうどよいですね。
bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0tag:blogger.com,1999:blog-30507925.post-71268606443302178912021-07-30T22:45:00.002+09:002021-07-30T22:45:48.700+09:00PyTorchでMNISTPyTorchでMNISTを動かしてみました。CPUのみで動作します。
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre class="highlight"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67</pre></div></td><td class="code"><div class="highlight"><pre class="highlight"><span></span><span class="c1">#</span>
<span class="c1"># Ref: https://github.com/pytorch/examples/blob/master/mnist/main.py</span>
<span class="c1"># Ref: https://qiita.com/ryu1104/items/76126a1d2ce22c59fe97</span>
<span class="c1">#</span>
<span class="c1"># Requirements:</span>
<span class="c1"># pyenvでpythonをインストールするときはliblzma-devが必要。</span>
<span class="c1"># pip install pylzma</span>
<span class="kn">import</span> <span class="nn">torch</span>
<span class="kn">import</span> <span class="nn">torch.nn</span> <span class="k">as</span> <span class="nn">nn</span>
<span class="kn">import</span> <span class="nn">torch.nn.functional</span> <span class="k">as</span> <span class="nn">F</span>
<span class="kn">from</span> <span class="nn">torch.utils.data</span> <span class="kn">import</span> <span class="n">DataLoader</span>
<span class="kn">from</span> <span class="nn">torchvision</span> <span class="kn">import</span> <span class="n">datasets</span><span class="p">,</span> <span class="n">transforms</span>
<span class="k">class</span> <span class="nc">Model</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">conv1</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">stride</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">conv2</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">stride</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">linear1</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">2048</span><span class="p">,</span> <span class="mi">256</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">linear2</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">256</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">dropout1</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Dropout</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">F</span><span class="o">.</span><span class="n">leaky_relu</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conv1</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">negative_slope</span><span class="o">=</span><span class="mf">0.02</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">F</span><span class="o">.</span><span class="n">leaky_relu</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conv2</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">negative_slope</span><span class="o">=</span><span class="mf">0.02</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">flatten</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">dropout1</span><span class="p">(</span><span class="n">F</span><span class="o">.</span><span class="n">leaky_relu</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">linear1</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">negative_slope</span><span class="o">=</span><span class="mf">0.02</span><span class="p">))</span>
<span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">linear2</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="k">return</span> <span class="n">x</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">torch</span><span class="o">.</span><span class="n">manual_seed</span><span class="p">(</span><span class="mi">123</span><span class="p">)</span>
<span class="n">dataset_train</span> <span class="o">=</span> <span class="n">datasets</span><span class="o">.</span><span class="n">MNIST</span><span class="p">(</span><span class="n">root</span><span class="o">=</span><span class="s2">"./data"</span><span class="p">,</span> <span class="n">train</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">download</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">transform</span><span class="o">=</span><span class="n">transforms</span><span class="o">.</span><span class="n">ToTensor</span><span class="p">())</span>
<span class="n">dataset_test</span> <span class="o">=</span> <span class="n">datasets</span><span class="o">.</span><span class="n">MNIST</span><span class="p">(</span><span class="n">root</span><span class="o">=</span><span class="s2">"./data"</span><span class="p">,</span> <span class="n">train</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">download</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">transform</span><span class="o">=</span><span class="n">transforms</span><span class="o">.</span><span class="n">ToTensor</span><span class="p">())</span>
<span class="n">loader_train</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">dataset_train</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">32</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">loader_test</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">dataset_test</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">128</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">Model</span><span class="p">()</span>
<span class="n">opt</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">Adam</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="mf">0.001</span><span class="p">)</span>
<span class="k">for</span> <span class="n">epoch</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
<span class="n">model</span><span class="o">.</span><span class="n">train</span><span class="p">()</span>
<span class="n">loss_train</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">batch_index</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">loader_train</span><span class="p">):</span>
<span class="n">opt</span><span class="o">.</span><span class="n">zero_grad</span><span class="p">()</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">loss</span> <span class="o">=</span> <span class="n">F</span><span class="o">.</span><span class="n">cross_entropy</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">reduction</span><span class="o">=</span><span class="s2">"sum"</span><span class="p">)</span>
<span class="n">loss_train</span> <span class="o">+=</span> <span class="n">loss</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
<span class="n">loss</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
<span class="n">opt</span><span class="o">.</span><span class="n">step</span><span class="p">()</span>
<span class="n">loss_train</span> <span class="o">/=</span> <span class="nb">len</span><span class="p">(</span><span class="n">loader_train</span><span class="o">.</span><span class="n">dataset</span><span class="p">)</span>
<span class="c1"># Test</span>
<span class="n">model</span><span class="o">.</span><span class="n">eval</span><span class="p">()</span>
<span class="n">loss_test</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">correct</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">with</span> <span class="n">torch</span><span class="o">.</span><span class="n">no_grad</span><span class="p">():</span>
<span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">loader_test</span><span class="p">:</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">loss_test</span> <span class="o">+=</span> <span class="n">F</span><span class="o">.</span><span class="n">cross_entropy</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">reduction</span><span class="o">=</span><span class="s2">"sum"</span><span class="p">)</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
<span class="n">pred</span> <span class="o">=</span> <span class="n">y</span><span class="o">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">dim</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">keepdim</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="n">view_as</span><span class="p">(</span><span class="n">pred</span><span class="p">)</span>
<span class="n">correct</span> <span class="o">+=</span> <span class="n">pred</span><span class="o">.</span><span class="n">eq</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
<span class="n">loss_test</span> <span class="o">/=</span> <span class="nb">len</span><span class="p">(</span><span class="n">loader_test</span><span class="o">.</span><span class="n">dataset</span><span class="p">)</span>
<span class="n">acc_test</span> <span class="o">=</span> <span class="mf">100.0</span> <span class="o">*</span> <span class="n">correct</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">loader_test</span><span class="o">.</span><span class="n">dataset</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"epoch=</span><span class="si">{}</span><span class="s2"> loss_train=</span><span class="si">{}</span><span class="s2"> loss_test=</span><span class="si">{}</span><span class="s2"> acc_test=</span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">epoch</span><span class="p">,</span> <span class="n">loss_train</span><span class="p">,</span> <span class="n">loss_test</span><span class="p">,</span> <span class="n">acc_test</span><span class="p">))</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</pre></div>
</td></tr></table>
<p/>
実行すると、
<pre class="code">
epoch=0 loss_train=0.15844096369811644 loss_test=0.04875367822442204 acc_test=98.39
epoch=1 loss_train=0.05745177720999345 loss_test=0.03826701421057806 acc_test=98.81
epoch=2 loss_train=0.04121023142867489 loss_test=0.03071835657870397 acc_test=98.93
epoch=3 loss_train=0.03073415454996381 loss_test=0.031469110992277276 acc_test=99.05
epoch=4 loss_train=0.024984311143002317 loss_test=0.033686953871918376 acc_test=99.04
epoch=5 loss_train=0.02134333044563282 loss_test=0.04148742442613293 acc_test=98.79
epoch=6 loss_train=0.017344313688603386 loss_test=0.043801980772903655 acc_test=98.99
epoch=7 loss_train=0.015290370488148755 loss_test=0.04075671738231176 acc_test=99.09
epoch=8 loss_train=0.0152512503207066 loss_test=0.04280102529609985 acc_test=99.0
epoch=9 loss_train=0.015672046943081695 loss_test=0.043737064159646434 acc_test=98.98
</pre>
となります。bluewidzhttp://www.blogger.com/profile/17816726155715820833noreply@blogger.com0