勉強しないとな~blog

ちゃんと勉強せねば…な電気設計エンジニアです。

超電導リニアL0系改良型試験車作った & OAK-D S2でステレオ撮影

今回もライトな工作ネタ。

やったこと

リニア新幹線ペーパークラフトがあったので、家族みんなインフルかかってしまったときに暇つぶしで作成した。

recommend.jr-central.co.jp

ついでに、最近カメラでのステレオ計測に興味があるので、OAK-D S2でとりあえず撮影した。
あとで3次元データ構築できるのかやってみたい。

ペーパークラフト仕上がり

作ったペーパークラフトの写真。

本体

細長い形状が再現されていて、複雑な面形状もある程度再現されている。いい感じ。
普通のペラペラのA4コピー用紙で作ったので、そこまで折り曲げたりが大変ということもなく。
強度はない。

駅のプラットホームも付属している。

乗客も簡単に作ってある。

レールにぴったりL0系本体が収まる。
乗降口までトンネルみたいなのでつながっているが、実際もこうなるのか?

OAK-D S2撮影

OAK-D S2を使って、ステレオカメラ(モノクロx2)の画像を取得する。
以下はjupyter上で実行した。

import cv2
import depthai as dai
from matplotlib import pyplot as plt
%matplotlib inline
# パイプライン作成
pipeline = dai.Pipeline()

# ノード定義
monoLeft  = pipeline.create(dai.node.MonoCamera)
monoRight = pipeline.create(dai.node.MonoCamera)
xoutLeft  = pipeline.create(dai.node.XLinkOut)
xoutRight = pipeline.create(dai.node.XLinkOut)

xoutLeft.setStreamName("left")
xoutRight.setStreamName("right")

# プロパティ設定
monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
# 解像度はS2のステレオ標準 720p 相当
monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)
monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_720_P)

# リンク
monoLeft.out.link(xoutLeft.input)
monoRight.out.link(xoutRight.input)
C:\Users\a\AppData\Local\Temp\ipykernel_33940\1103263992.py:14: DeprecationWarning: LEFT is deprecated, use CAM_B or address camera by name  instead.
  monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
C:\Users\a\AppData\Local\Temp\ipykernel_33940\1103263992.py:15: DeprecationWarning: RIGHT is deprecated, use CAM_C or address camera by name  instead.
  monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)

バイス接続する。
よく失敗するが、だめだったらOAK-D S2をPCにつなぎなおす。
だいたい成功するときは3秒でつながる。それ以上だったら失敗する。

device = dai.Device(pipeline)

キューを定義する。ここから画像が取り出せる。

qLeft  = device.getOutputQueue(name="left",  maxSize=4, blocking=False)
qRight = device.getOutputQueue(name="right", maxSize=4, blocking=False)

キューから、tryGetAll()で全画像取り出して、先頭の画像だけ使う。

inLeft  = qLeft.tryGetAll()
inRight = qRight.tryGetAll()

frameLeft  = inLeft[0].getCvFrame()
frameRight = inRight[0].getCvFrame()
plt.figure(figsize=(6.4*2, 4.8))
plt.subplot(1,2,1)
plt.imshow(frameLeft, cmap='gray')
plt.axis('off')

plt.subplot(1,2,2)
plt.imshow(frameRight, cmap='gray')
plt.axis('off')

plt.tight_layout()
plt.show()

なんだか左カメラがボケてる感じ・・・

とりあえず画像が取得できたので、保存しておく。

cv2.imwrite('image1_left.jpg', frameLeft)
cv2.imwrite('image1_right.jpg', frameRight)
True

別の画像も撮っておく。

inLeft  = qLeft.tryGetAll()
inRight = qRight.tryGetAll()

frameLeft  = inLeft[0].getCvFrame()
frameRight = inRight[0].getCvFrame()
plt.figure(figsize=(6.4*2, 4.8))
plt.subplot(1,2,1)
plt.imshow(frameLeft, cmap='gray')
plt.axis('off')

plt.subplot(1,2,2)
plt.imshow(frameRight, cmap='gray')
plt.axis('off')

plt.tight_layout()
plt.show()

cv2.imwrite('image2_left.jpg', frameLeft)
cv2.imwrite('image2_right.jpg', frameRight)
True

カメラを使い終わったらクローズしておく。

device.close()

以上

出来のいいペーパークラフトが無料配布されていてうれしい。

今回撮影したステレオ画像で3次元データ構築してみたい。

文言(wenyan)で遊んでみる

ちょっと古い記事だけど、漢文風のプログラミング言語があって、面白そうなのでやってみた。

漢文風のプログラミング言語「文言(wenyan-lang)」がめっちゃエモいと話題に - やじうまの杜 - 窓の杜

参考にしたもの

Qiitaの記事も見たが、本家のドキュメントも見てみた。
説明自体も漢文でびびるけど、なんとなく読める。

文言(wenyan‑lang)で簡単なプログラムを書いてみる #初心者 - Qiita

Home · wenyan-lang/wenyan Wiki · GitHub

Syntax Cheatsheet · wenyan-lang/wenyan Wiki · GitHub

GitHub - wenyan-lang/wenyan: 文言文編程語言 A programming language for the ancient Chinese.

実行環境

オンラインでのデモ版、でもこれで十分

文言 Wenyan Online IDE

色々試し

helloworld

まずはhelloworld。サンプルそのまま。

吾有一數。曰三。名之曰「甲」。
為是「甲」遍。
    吾有一言。曰「「問天地好在。」」。書之。
云云。
問天地好在。
問天地好在。
問天地好在。

"Hello world"の訳し方がエモい。
でも自分じゃこんなの書けない。

コメントアウト

注曰。でコメントになる。

注曰。吾有一數。曰三。名之曰「甲」。
吾有一數。曰五。名之曰「甲」。
為是「甲」遍。
    吾有一言。曰「「問天地好在。」」。書之。
云云。
問天地好在。
問天地好在。
問天地好在。
問天地好在。
問天地好在。

他にも2パターンコメントアウトのしかたが書かれてたが、注曰。だけ覚えておけばいいと思う。
最後のやつは漢字が読めないので、入力自体困難。

  • 批曰。
  • 疏曰。

文字列の演算

文字列に加算できるみたいなので試し。

helloworld的な文字列に1を追加してく。
まずこの文字列に変数名付ける。 ・・・「問天」
これに加算して、昔之~の記述で、元の「問天」をそれで上書きする。
最後に、を書いて、書之で表示する。

吾有一數。曰五。名之曰「甲」。
吾有一言。曰「「問天地好在。」」。名之曰「問天」。
為是「甲」遍。
    加「問天」以一。昔之「問天」者今其是矣。
    夫「問天」。書之。
云云。
問天地好在。1
問天地好在。11
問天地好在。111
問天地好在。1111
問天地好在。11111

追記されるのが半角数字だったのでちょっと期待外。

ループ変数

ループ変数は自分で作らないといけない?

吾有一數。曰一。名之曰「甲」。
吾有一言。曰「「問天地好在。」」。名之曰「問天」。
為是五遍。
    加「問天」以「甲」。書之。
    加「甲」以一。昔之「甲」者今其是矣。
云云。
問天地好在。1
問天地好在。2
問天地好在。3
問天地好在。4
問天地好在。5

以上

気が向いて、あとは作るネタが思い付けば続けるかな。

GenAI Processorsやってみる -1. 導入、テキスト入出力

Google がGenAI Processorsというものを出したそうで、自分で生成AI使ったアプリ作れるそうなので、試してみる。

このページも参考に。

GenAI Processorsで遊ぼう!コピペで試せるAIアプリ4選(PDF要約・翻訳・画像生成も!?) #Python - Qiita

APIキー作成

まずAPIキーを作成しておく必要がある。

Google AI Studioから発行する。

Get API key | Google AI Studio

無料枠あるそうなのでそれでやってく

どれくらいある?

Gemini API無料|制限・料金・APIキー取得方法を図解 | Hakky Handbook

ひとまず、軽いモデル(Gemini 2.0 Flash-Lite)なら一日1500リクエスト投げて大丈夫そう

モデル リクエスト数 (RPM) リクエスト数 (RPD) トークン数 (トークン/分)
Gemini 2.5 Pro Experimental 5 - 1,000,000
Gemini 2.0 Flash 15 - 1,000,000
Gemini 2.0 Flash-Lite - 1,500 1,000,000
Gemma 3 - 14,400 15,000

あとは無料にしてもクレジットカード登録必要か?と思ったが、ここには特に書かれてないので、これで進めてみる

Google Colabで試し

GitHub - google-gemini/genai-processors: GenAI Processors is a lightweight Python library that enables efficient, parallel content processing.

GitHub公式ページを見ると、notebooksディレクトリにipynbファイルがあって、チュートリアルを試せる。Google Colabですぐ開けるので、Colab使ってみるがてら、それで試してみる。

Google Colab開くが、実体はどこにあるのか?GitHubにある?自分のアカウントにコピーしないといけない?

開いたノートブックは、「ドライブにコピー」すれば自分のアカウントに持ってこれるよう

「ドライブにコピー」したら、自分のGoogleドライブに、"Colab Notebooks"フォルダができて、そこにコピーされた。(デフォルトだとファイル名に「のコピー」が付いていたので消した)

ColabでAPIキー設定

Colab上でのAPIキーの使い方が分からなかったが、左側の"Secret"のアイコンで設定できる

APIキーのコードをコピーせずとも、Googleアカウント経由で取ってこれるよう

チュートリアルよく分からん・・・

asyncの使い方とか、概念の理解が難しい。

自分で新しくノートブック作って、自分の試してみたいことを自分なりに試してみる。

テキスト、音声、画像を入出力できる、GeminiとかのAIモデルを呼べる、ということと思う。
あとは非同期処理で、うまく同時進行できる、という感じか。

以下、Colabの新規ノートブックで

まず環境準備

!pip install genai-processors

長いのでクリックで開閉式

Collecting genai-processors
  Downloading genai_processors-1.1.0-py3-none-any.whl.metadata (2.6 kB)
Requirement already satisfied: absl-py>=1.0.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (1.4.0)
Collecting dataclasses-json>=0.6.0 (from genai-processors)
  Downloading dataclasses_json-0.6.7-py3-none-any.whl.metadata (25 kB)
Requirement already satisfied: google-genai>=1.16.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (1.31.0)
Requirement already satisfied: google-api-python-client>=0.6.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (2.179.0)
Collecting google-cloud-texttospeech>=2.27.0 (from genai-processors)
  Downloading google_cloud_texttospeech-2.27.0-py3-none-any.whl.metadata (9.6 kB)
Requirement already satisfied: google-cloud-speech>=2.33.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (2.33.0)
Requirement already satisfied: httpx>=0.24.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (0.28.1)
Requirement already satisfied: jinja2>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (3.1.6)
Requirement already satisfied: opencv-python>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (4.12.0.88)
Requirement already satisfied: numpy>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (2.0.2)
Collecting pdfrw>=0.4 (from genai-processors)
  Downloading pdfrw-0.4-py2.py3-none-any.whl.metadata (32 kB)
Requirement already satisfied: Pillow>=9.0.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (11.3.0)
Requirement already satisfied: termcolor>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (3.1.0)
Collecting pypdfium2>=4.30.0 (from genai-processors)
  Downloading pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (48 kB)
[2K     [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m48.5/48.5 kB[0m [31m3.1 MB/s[0m eta [36m0:00:00[0m
[?25hRequirement already satisfied: xxhash>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from genai-processors) (3.5.0)
Collecting marshmallow<4.0.0,>=3.18.0 (from dataclasses-json>=0.6.0->genai-processors)
  Downloading marshmallow-3.26.1-py3-none-any.whl.metadata (7.3 kB)
Collecting typing-inspect<1,>=0.4.0 (from dataclasses-json>=0.6.0->genai-processors)
  Downloading typing_inspect-0.9.0-py3-none-any.whl.metadata (1.5 kB)
Requirement already satisfied: httplib2<1.0.0,>=0.19.0 in /usr/local/lib/python3.12/dist-packages (from google-api-python-client>=0.6.0->genai-processors) (0.22.0)
Requirement already satisfied: google-auth!=2.24.0,!=2.25.0,<3.0.0,>=1.32.0 in /usr/local/lib/python3.12/dist-packages (from google-api-python-client>=0.6.0->genai-processors) (2.38.0)
Requirement already satisfied: google-auth-httplib2<1.0.0,>=0.2.0 in /usr/local/lib/python3.12/dist-packages (from google-api-python-client>=0.6.0->genai-processors) (0.2.0)
Requirement already satisfied: google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0,>=1.31.5 in /usr/local/lib/python3.12/dist-packages (from google-api-python-client>=0.6.0->genai-processors) (2.25.1)
Requirement already satisfied: uritemplate<5,>=3.0.1 in /usr/local/lib/python3.12/dist-packages (from google-api-python-client>=0.6.0->genai-processors) (4.2.0)
Requirement already satisfied: proto-plus<2.0.0,>=1.22.3 in /usr/local/lib/python3.12/dist-packages (from google-cloud-speech>=2.33.0->genai-processors) (1.26.1)
Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<7.0.0,>=3.20.2 in /usr/local/lib/python3.12/dist-packages (from google-cloud-speech>=2.33.0->genai-processors) (5.29.5)
Requirement already satisfied: anyio<5.0.0,>=4.8.0 in /usr/local/lib/python3.12/dist-packages (from google-genai>=1.16.0->genai-processors) (4.10.0)
Requirement already satisfied: pydantic<3.0.0,>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from google-genai>=1.16.0->genai-processors) (2.11.7)
Requirement already satisfied: requests<3.0.0,>=2.28.1 in /usr/local/lib/python3.12/dist-packages (from google-genai>=1.16.0->genai-processors) (2.32.4)
Requirement already satisfied: tenacity<9.2.0,>=8.2.3 in /usr/local/lib/python3.12/dist-packages (from google-genai>=1.16.0->genai-processors) (8.5.0)
Requirement already satisfied: websockets<15.1.0,>=13.0.0 in /usr/local/lib/python3.12/dist-packages (from google-genai>=1.16.0->genai-processors) (15.0.1)
Requirement already satisfied: typing-extensions<5.0.0,>=4.11.0 in /usr/local/lib/python3.12/dist-packages (from google-genai>=1.16.0->genai-processors) (4.15.0)
Requirement already satisfied: certifi in /usr/local/lib/python3.12/dist-packages (from httpx>=0.24.0->genai-processors) (2025.8.3)
Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.12/dist-packages (from httpx>=0.24.0->genai-processors) (1.0.9)
Requirement already satisfied: idna in /usr/local/lib/python3.12/dist-packages (from httpx>=0.24.0->genai-processors) (3.10)
Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.12/dist-packages (from httpcore==1.*->httpx>=0.24.0->genai-processors) (0.16.0)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.12/dist-packages (from jinja2>=3.0.0->genai-processors) (3.0.2)
Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.12/dist-packages (from anyio<5.0.0,>=4.8.0->google-genai>=1.16.0->genai-processors) (1.3.1)
Requirement already satisfied: googleapis-common-protos<2.0.0,>=1.56.2 in /usr/local/lib/python3.12/dist-packages (from google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0,>=1.31.5->google-api-python-client>=0.6.0->genai-processors) (1.70.0)
Requirement already satisfied: grpcio<2.0.0,>=1.33.2 in /usr/local/lib/python3.12/dist-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-speech>=2.33.0->genai-processors) (1.74.0)
Requirement already satisfied: grpcio-status<2.0.0,>=1.33.2 in /usr/local/lib/python3.12/dist-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0,>=1.34.1->google-cloud-speech>=2.33.0->genai-processors) (1.71.2)
Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0,>=1.32.0->google-api-python-client>=0.6.0->genai-processors) (5.5.2)
Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.12/dist-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0,>=1.32.0->google-api-python-client>=0.6.0->genai-processors) (0.4.2)
Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.12/dist-packages (from google-auth!=2.24.0,!=2.25.0,<3.0.0,>=1.32.0->google-api-python-client>=0.6.0->genai-processors) (4.9.1)
Requirement already satisfied: pyparsing!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3,<4,>=2.4.2 in /usr/local/lib/python3.12/dist-packages (from httplib2<1.0.0,>=0.19.0->google-api-python-client>=0.6.0->genai-processors) (3.2.3)
Requirement already satisfied: packaging>=17.0 in /usr/local/lib/python3.12/dist-packages (from marshmallow<4.0.0,>=3.18.0->dataclasses-json>=0.6.0->genai-processors) (25.0)
Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.12/dist-packages (from pydantic<3.0.0,>=2.0.0->google-genai>=1.16.0->genai-processors) (0.7.0)
Requirement already satisfied: pydantic-core==2.33.2 in /usr/local/lib/python3.12/dist-packages (from pydantic<3.0.0,>=2.0.0->google-genai>=1.16.0->genai-processors) (2.33.2)
Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.12/dist-packages (from pydantic<3.0.0,>=2.0.0->google-genai>=1.16.0->genai-processors) (0.4.1)
Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests<3.0.0,>=2.28.1->google-genai>=1.16.0->genai-processors) (3.4.3)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests<3.0.0,>=2.28.1->google-genai>=1.16.0->genai-processors) (2.5.0)
Collecting mypy-extensions>=0.3.0 (from typing-inspect<1,>=0.4.0->dataclasses-json>=0.6.0->genai-processors)
  Downloading mypy_extensions-1.1.0-py3-none-any.whl.metadata (1.1 kB)
Requirement already satisfied: pyasn1<0.7.0,>=0.6.1 in /usr/local/lib/python3.12/dist-packages (from pyasn1-modules>=0.2.1->google-auth!=2.24.0,!=2.25.0,<3.0.0,>=1.32.0->google-api-python-client>=0.6.0->genai-processors) (0.6.1)
Downloading genai_processors-1.1.0-py3-none-any.whl (219 kB)
[2K   [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m219.9/219.9 kB[0m [31m10.2 MB/s[0m eta [36m0:00:00[0m
[?25hDownloading dataclasses_json-0.6.7-py3-none-any.whl (28 kB)
Downloading google_cloud_texttospeech-2.27.0-py3-none-any.whl (189 kB)
[2K   [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m189.4/189.4 kB[0m [31m11.3 MB/s[0m eta [36m0:00:00[0m
[?25hDownloading pdfrw-0.4-py2.py3-none-any.whl (69 kB)
[2K   [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m69.5/69.5 kB[0m [31m3.9 MB/s[0m eta [36m0:00:00[0m
[?25hDownloading pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB)
[2K   [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m2.8/2.8 MB[0m [31m50.4 MB/s[0m eta [36m0:00:00[0m
[?25hDownloading marshmallow-3.26.1-py3-none-any.whl (50 kB)
[2K   [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m50.9/50.9 kB[0m [31m3.3 MB/s[0m eta [36m0:00:00[0m
[?25hDownloading typing_inspect-0.9.0-py3-none-any.whl (8.8 kB)
Downloading mypy_extensions-1.1.0-py3-none-any.whl (5.0 kB)
Installing collected packages: pdfrw, pypdfium2, mypy-extensions, marshmallow, typing-inspect, dataclasses-json, google-cloud-texttospeech, genai-processors
Successfully installed dataclasses-json-0.6.7 genai-processors-1.1.0 google-cloud-texttospeech-2.27.0 marshmallow-3.26.1 mypy-extensions-1.1.0 pdfrw-0.4 pypdfium2-4.30.0 typing-inspect-0.9.0

from google.colab import userdata

API_KEY = userdata.get('GOOGLE_API_KEY')

まず簡単にGeminiを呼び出して、テキスト入力、テキスト出力させる。

from genai_processors.core import genai_model
from google.genai import types as genai_types

# Initialize the GenAI model processor
# Replace 'gemini-2.0-flash' with your desired model name
genai_processor = genai_model.GenaiModel(
    api_key=API_KEY,
    model_name="gemini-2.0-flash",
    generate_content_config=genai_types.GenerateContentConfig(temperature=0.7),
)

入力には、genai_processorsのstreamsを使わないといけないようなので、それで入力を構築する。
入力は単語で区切ったりする?文章でも大丈夫?確認してみる。

from genai_processors import streams

input_parts = ["Hello", "World"]
input_stream = streams.stream_content(input_parts)

async使うのにimport asyncioしないといけない?

import asyncio
async for part in genai_processor(input_stream):
  print(part.text)
Hello
 World! How can I help you today?
input_parts = ["Hello. What's your name?"]
input_stream = streams.stream_content(input_parts)
async for part in genai_processor(input_stream):
  print(part.text)
I
 am a large
 language model, trained by Google. I don't have a name in the
 traditional sense. You can just call me Google's AI.
input_parts = ["Hello.", "What's", "your", "name?"]
input_stream = streams.stream_content(input_parts)
async for part in genai_processor(input_stream):
  print(part.text)
I
 am a large
 language model, trained by Google. I don't have a personal name.

どう区切っても大丈夫なよう。

以上

次は音声か画像の入出力やってく。

ずっとColab上でやってるのでいいか?アプリ化しようと思ったらローカルで動かしたほうがいいかも。

ゼロから作るDeep Learningやる - 8章 ディープラーニング

ゼロから作るDeep Learningの学習メモ続き。
今回もコードはなし。内容的にも、知識的なもの。
今回で最後の章になる。

GitHub公開のソースコード(MITライセンス)

github.com

著作権表示、ライセンス文書

Copyright (c) 2016 Koki Saitoh

deep-learning-from-scratch/LICENSE.md at master · oreilly-japan/deep-learning-from-scratch · GitHub

8章 ディープラーニング

章タイトルが「ディープラーニング」だが、自分としては「ディープラーニングの発展と今後」のように認識した。

認識精度向上について

  • MNIST手書き文字認識だと、6層のConv(その間にReLUはあって、その後にPoolingがあったりなかったり)と2層のAffine(その後にReLU、Dropout、Softmax)で、99%以上の認識精度が出せるよう。
  • さらに精度を上げようと思うと、Data Augmentation(データ拡張)が一つの手法。(画像に回転、シフト、クロップなど色々な変化を加えて学習画像の枚数を増やす)

「層数」について

ニューラルネットワークの層数をどう数えるのか?と思って調べたが、あまり明確な情報は得られず。

下記サイトだと、活性化関数とかの層も込みで「層」と言っている。

層 (layers) : ディープラーニングの層の種類まとめ | CVMLエキスパートガイド

層の中でも、学習するパラメータの有無での分類はあるよう。
ConvやAffine(他のサイトとか、KerasフレームワークだとDenseと記載されている)はパラメータがあるが、Pooling、活性化関数などはパラメータはない。
ドロップアウト層も、前にこのテキストで読んだところでは、スケーリングとシフトのパラメータがある、と書かれていたが、Kerasではないよう。
また、Kerasだと、活性化関数はConv層とかの中に含められている。

深層学習モデルのパラメータの数を数える #Python - Qiita

VGGネットワーク(後で紹介)だと、バリエーションはあるが、VGG-16だと、16というのは学習可能な層だけを数えているとのこと。

VGGNet: 初期の定番CNN | CVMLエキスパートガイド

「層を深くすること」の重要性

理論的にはあまり多くはわかっていないが、利点の一つとして、浅いニューラルネットワークと同等な認識をより少ないパラメータで行うことができる、ということが言及されている。

学習効率が上がる、とも言われている。上記のようにパラメータ数が減るのと、演算のレイヤごとに解くべき問題を分割できる、というのが理由のよう。

代表的なCNN

この本の執筆時点(2015年)で有名な3つが紹介されている。

  • VGG
    Conv層とPooling層、最後に全結合層がある構成。層数(学習可能なもの)は16と19が有名だけど、論文では11、13、16、19層で、CNN層のカーネルサイズ、チャンネル数のバリエーションも含めて6パターンは試されているよう。
    AI画像認識で知っておきたい有名なCNNアーキテクチャー - 半導体事業 - マクニカ
    深層学習論文の読解(VGG) #DeepLearning - Qiita
    同時期に出たGoogLeNetにILSVRC2014で負けたが、シンプルな構成で応用性が高く、使われることが多いとのこと。自分も学会参加したときにVGGをベースに使っている研究を見たことがあった気がする。

  • GoogLeNet
    VGGより複雑になっている。インセプション構造(サイズの異なるフィルタの結果を統合している)を入れている。

  • ResNet
    Microsoftのチームが開発。スキップ構造の導入で、学習のときの勾配消失に対応している。150層以上でも、実験では認識精度が向上し続けたとのこと。ILSVRC2015で3.5%の誤認識率を出した。

学習、推論の高速化

  • AlexNetの推論だと、全体の処理のうち畳み込み層の処理の時間割合が高く、GPUでは95%、CPUでは89%になるとのこと。学習時も同様に畳み込み層が重いとのこと。

GPUでの高速化

  • CPUとGPUの学習時間を比較すると、40日以上 vs 6日 ぐらいの差が出る。(16-core Xeon vs Titan)
  • さらにcuDNN(CUDA上で動作する、ディープラーニングに最適化されたライブラリ)を使うと、2.5日ぐらいまで短縮する。

分散学習での高速化

  • 分散学習でも高速化する。計算の分散のさせ方は難しいようだが、TensorFlowとかでは内部的にやってくれるよう。
  • AWSとかだとどうなるのか?分散学習のツールとか用意あってもおかしくなさそう。

演算ビット数の削減での高速化

  • ディープラーニングだと、半精度(16bit)でも十分という話もある。
  • NVIDIAPascalアーキテクチャでは半精度がサポートされる。
  • YOLOを動かしたとき、halfという設定もあったが、半精度を使える環境なら高速化できるかもしれない。

ディープラーニングの実用例

  • ここまでは画像分類だけだったが、物体検出、セグメンテーションなどにもここで言及されている。
    • 物体検出: 物体の位置の特定も含めてクラス分類を行う。R-CNNではSVMなど古典的な手法で候補を抽出した後にCNNで分類を行う。Faster R-CNNでは、物体候補もCNNで出している。
    • セグメンテーション: ピクセルごとに分類すればできるが、時間の効率が悪い。FCN(Fully Convolutional Network)で改善できる。FCNを使うと、全ピクセルforward()推論が1回のforward()で済んで、改善されている。
  • あとは画像キャプション生成、画像生成、ディープラーニングを使った強化学習など応用が色々紹介されているが、今はこのテキストの記載よりかなり進んでしまっている。ので他のテキストとか、論文とか色々読んでいきたい。

以上

ひとまずテキスト終わり!
ディープラーニングのネットワークの中身とか、学習の手法・用語を覚えたので、自分で学習データを使ってファインチューニングする、ということをやってみたい。

ゼロから作るDeep Learningやる - 7章 畳み込みニューラルネットワーク

ゼロから作るDeep Learningの学習メモ続き。
今回もコードはなし。コード書くのが面倒 考え方の理解が優先で。

GitHub公開のソースコード(MITライセンス)

github.com

著作権表示、ライセンス文書

Copyright (c) 2016 Koki Saitoh

deep-learning-from-scratch/LICENSE.md at master · oreilly-japan/deep-learning-from-scratch · GitHub

7章 畳み込みニューラルネットワーク

画像認識で使われるCNNの勉強。なんとなくの事前知識はあるので、あまり知らなかったところを補う。

構成要素

ConvolutionレイヤとPoolingレイヤが主な構成要素。

Convolutionレイヤ

  • パディング、ストライドという、Affineレイヤにはない設定項目あり。
    • パディング:入力画像の周囲に固定データをくっつけるもの。出力のサイズが変わる。主にConvolutionのフィルタをかけると出力サイズが縮小してしまうのを補うのが目的と思われる。
    • ストライド:Convolutionかけていくときに、縦横何ピクセルずつ動かしていくか、の設定。1ピクセルずつ動かすのと比べて、間引かれた形になる。大きいフィルタサイズに対してちまちま動かしても意味がない、というのと、出力を間引いて演算量を減らすのが目的、かな?
    • パディング、ストライド、フィルタサイズから、出力のサイズが計算できる。
       OH = \frac{H + 2P -FH}{S} + 1 (幅方向に対して。高さ方向には、 H \rightarrow Wと置き換えするだけ。)
  • Convolutionは、チャネル(RGB)の次元も考えると、3次元の畳み込みになる。入力画像もフィルタ画像も2次元配列がチャネル数(普通のRGBだと3)だけ並んでて、対応する要素ごとに掛け算して総和を取るだけ。出力からチャネルの次元はなくなる。図でイメージするとわかりやすい。(図は簡単に描くために、 FH = FW = Sと、オーバーラップなしにしている。)
  • フィルタ数を増やすと、出力にその次元が追加になる。図イメージで言うと、出力が3次元になる。
  • 入力データがバッチデータになるパターンもあるが、入出力がその分繰り返しになる。次元は、4次元になるので、ちょっと図にはしにくい。
  • バイアス項も存在する。1ウィンドウごとに固定の値を加算する。全ウィンドウで一律の加算値。
  • Convolution演算は、実装上は、一度入力画像の1ウィンドウを1次元に直して、フィルタも1次元に直して実施されている。チャンネル、バッチの次元も合わせて、入力は結局2次元配列になり、フィルタもフィルタ数の次元と合わせて2次元となる。ということで、普通の行列積で計算できる。
    その実装方法で考えると、Convolution演算も前に出たAffineレイヤーとほぼ同じ演算になり、バックプロパゲーションも同じように考えられる。
    ※今はPyTorchやTensorFlowのフレームワークを使えば、画像の畳み込み演算の実装を気にする必要はないし、内部的にもcuDNNとかでは1次元に直すようなことはしていないらしい。
    この辺りとか参考。
    Convolutional Layers User's Guide - NVIDIA Docs

Poolingレイヤ

  • アベレージによるPoolingもあるが、基本的にはMax Poolingが主に使われる。単にPoolingと言ったらMax Poolingのことになる。なんでMax Poolingがいいかというのは、前に読んだテキストに記載があったような。
    「何かがある」を検出しているところを選ぶのが、物体検出に適している、ということだったかと思う。

https://sourestdeeds.github.io/pdf/Deep%20Learning%20with%20Python.pdf

  • Poolingにはパラメータはない。(ストライドは、前段のConvolutionレイヤのものを使う)

  • Poolingも、レイヤとして実装されている。パラメータはないが、Max演算をやっていることに伴って、バックプロパゲーションの際に最大値を取ったところだけ後段に伝播させる、という処理が入る。

    • 実装を見ると、arg_maxというメンバ変数があって、Max演算をやったときに各ウィンドウ内で最大値を取る位置のインデックスを保持している。(ウィンドウ数のサイズになっている。)forward()関数実行時に記録している。
    • backward()では、一旦numpy.zeros()で全要素0の配列を用意して、arg_maxで保持したインデックスのところだけ、伝播してきた微分の値を入れている。

学習結果の可視化

GradCAMという手法で可視化する例を見たことはあるが、このテキストでは、フィルタを画像として表示しているところまで。低いレイヤのところならこれで十分なのかも。

CNNの例

LeNet(1998年)、AlexNet(2012年)の2つが紹介されている。

  • LeNet: 手書き文字を認識するネットワークとして初めて提案されたCNN
  • AlexNet: ディープラーニングのブームの火付け役になったもの。Convolutionレイヤのフィルタ数を見ると、96→256→384→384→256と、それなりに大きい数を取っている。(今のネットワークだともっともっと大きい?)
    活性化関数にReLUを使う、ドロップアウトを使う、LRN(Local Response Normalization)を使うといった工夫が入っていたりする。

以上

あとは8章を読めば終わり!がんばろう。

ゼロから作るDeep Learningやる - 6章 学習に関するテクニック

ゼロから作るDeep Learningの学習メモ続き。
今回はコードなしで、自分の学び・気づきのメモだけ。

GitHub公開のソースコード(MITライセンス)

github.com

著作権表示、ライセンス文書

Copyright (c) 2016 Koki Saitoh

deep-learning-from-scratch/LICENSE.md at master · oreilly-japan/deep-learning-from-scratch · GitHub

6章 学習に関するテクニック

この章は、実際に学習をやる際のノウハウというか、単純にここまでのシンプルなやり方だと難点が出ることがあって、それについての対処法が紹介されている。
自分で学習をやるときの基礎知識になりそう。

勾配の降りていき方

今まで見たSGD(Stochastic Gradient Descent: Stochasticが付いてるのは、バッチデータを確率的に選んでることによる、全データを使って勾配を求めていたら、Stochasticが付かないと思われる)だと、動かす変数(=ネットワークのパラメータ)の現在地点での勾配の方向に更新を行う、というやり方だが、目的関数に対して変数ごとに異方性が大きいと、その地点での勾配が最小地点と結構ずれた方向を指してしまい、収束まで時間がかかる。そのために、更新方法の工夫がいくつか紹介されている。

  • Momentum: 変化のさせ方の変化のさせ方をその地点での勾配で更新する感じ?ボールがパラメータ空間中を転がっているイメージになるよう。
  • AdaGrad: パラメータの1要素ごとに、学習率を更新していく。パラメータの1要素ごとに勾配の2乗を足していって、それの逆数と固定の係数 \etaを学習率とする。偏微分が大きい(=更新具合の大きい)パラメータは学習率がすぐに小さくなっていく。
    • どんどん更新していくと、学習係数が0になって更新されなくなる問題がある。
    • 改善手法として、"RMSProp"が紹介されている。過去の勾配を徐々に忘れるようにするとのこと。指数関数的に減少させていくということなので、決まった定数を掛けていく感じかな?
  • Adam: 上記2つを組み合わせたようなもの、とのこと。

重みの初期化

重みの初期値も学習の収束に効いてくるとのこと。全部0とかにすると、全部同じように動いてしまって、きちんと学習できない。ということで、ランダムに初期値を設定して、均衡を崩す(?)ことが必要とのこと。

あと、活性化関数の形によっても適切なランダム分布のさせ方があるよう。ここでは、いずれも正規分布を使っていて(numpy.random.randn()で実装)、その分布幅(標準偏差)をどれくらいにするか、が焦点。平均は言及ないので、0にするということのよう。

  • シグモイド関数だと、前の層のノード数 nに対して、 \frac{1}{\sqrt{n}}標準偏差にするのがいいとのこと。・・・「Xavierの初期値」
  • ReLU関数だと、 \sqrt{\frac{2}{n}}標準偏差がいいとのこと。・・・「Heの初期値」

これらにより、学習に伴ってちゃんと損失関数が減少するか、どれくらいの速さで減少していくか、が変わる。

バッチノーマライゼーション

与えるバッチごとに、活性化関数の前か後かで、平均0、標準偏差1に正規化する。各層で適度な値の広がりを持たせるための工夫。
これにより、学習が速くなる、初期値依存が減る、過学習が抑制される、というメリットがあり、このテキスト執筆時点(2016年)では新しい手法だけれど広く使われている、と書かれている。

正規化に加えて、スケーリング、シフトも掛けられていて、これはネットワークのパラメータになる。
※バッチノーマライゼーションもレイヤーとして実装される
このパラメータについてもバックプロパゲーションの計算方法があり、参考文献も記載されているが、今はここまでの理解で。

推論のときはどう扱うのか?と思ったが、実装コードを見ると、runnning_meanrunnning_varというメンバ変数があり、これを学習のときに更新していって、推論のときに使うよう。
順方向の関数も、train_flgという引数が用意されていて、これによってrunnning_meanrunnning_varを更新するかどうかを決めている。

正則化

過学習を抑制することを目的に、重みのL2ノルムを損失関数に加算して、変に大きい値にならないようにする。バックプロパゲーションでは、各重みごとに単純に \lambda Wを加算するだけなので、計算は単純か。

"Weight Decay"(荷重減衰)として紹介されていて、「過学習抑制のために昔からよく用いられる手法」と書かれていて、Deep Learningに限らず使われる手法のよう。

Perplexityで調べてもらったまとめ。

荷重減衰は、数学的根拠を持ちながらも適用領域ごとに解釈が発展してきた汎用的な正則化手法です。古典的機械学習では明示的な正則化項として、ディープラーニングでは最適化プロセスの一部として機能し、いずれもモデルの汎化性能向上に寄与します。

ドロップアウト

これも過学習抑制の手法。
学習時に一部のニューロンを使わない(出力を次段に与えない)ようにする。テスト時は全ニューロンを使用する、ただし、出力に、学習時に消去しなかった割合を乗算して出力する。

「学習時に消去しなかった割合を乗算」が分からなかったが、コードの実装を見ると、全ニューロンの出力に、固定の倍率で、(1 - dropout_ratio)を掛けていた。

ドロップアウトもレイヤーとして実装されていて、バッチノーマライゼーションと同様にforward()関数にtrain_flg引数があって、学習時はランダムマスクを生成して入力に掛けて出力、テスト時は全入力に(1 - dropout_ratio)を掛けている。
(ランダムマスクは覚えておいて、バックプロパゲーションで使用している)

解釈としては、ドロップアウトすると、残りのニューロンで頑張って大きめに値を出そうとするので、テスト時は各ニューロンの出力を少し小さめに出すようにして、同等の出力が出るようにする、という感じ?

ドロップアウトの有無での比較もされてる。

  • MNISTデータセットで、少な目学習データ(300データ)、多少複雑なネットワーク(ノード数100のレイヤーを7層)で、過学習しやすい条件を作る
  • ドロップアウトなしだと、学習データに対して精度は1.0近くに達しているが、テストデータでの精度は0.8弱で飽和
  • ドロップアウトありだと、学習データに対する精度は、同じエポック数で1.0までなかなか達しないが、テストデータに対する精度は上昇し続けている

ハイパーパラメータの検証

学習レートとか、バッチサイズとか、ニューロン数とか、がハイパーパラメータに当たる。

このあたりをランダムに振って、かつ検証用データも用意して、いいところを探す。

全探索(グリッドサーチ)するより、ランダムサーチしたほうがいい結果が出るらしい。

細かい最適値を決めるというより、だいたいどのオーダーの値かざっくり探るものとのこと。値を振るときも、 10^{-1}, 10^{-2}, ...、など、対数的に等間隔に振る。

学習率、Weight Decay係数を例として挙げているが、層数とかニューロン数はそれだと難しいのでは?それはいくつかの値を決め打ちでやるぐらいか?

以上

なんとかゴールデンウィーク中にこのテキスト終わらせたい。

ゼロから作るDeep Learningやる - 5章 誤差逆伝播法

ゼロから作るDeep Learningの学習メモ続き。

GitHub公開のソースコード(MITライセンス)

github.com

著作権表示、ライセンス文書

Copyright (c) 2016 Koki Saitoh

deep-learning-from-scratch/LICENSE.md at master · oreilly-japan/deep-learning-from-scratch · GitHub

5章 誤差逆伝播

計算グラフ

厳密な数式より、計算グラフを使ったほうが分かりやすい、ということで、まず計算グラフの紹介があった。
買い物のときの支払金額の計算が例に上がっていた、なんとなく雰囲気は理解したような。

レイヤーのクラスのbackward()関数の実装で、doutdxという変数名が使われていたが、backward()関数がやるのは、入力がどれくらい変化したら出力が変化するか、その割合(出力の変化/入力の変化)で、
ついでにそのレイヤーの出力変化がネットワーク最終段の目的関数の変化に対してどれくらい効くか、その割合(目的関数の変化/レイヤー出力の変化)も掛けることで、レイヤーの入力変化 - 目的関数の変化の割合を出す、ということかと。

そうすると、backward()関数の出力は \frac{\partial L}{\partial w} のことを表すかと思い、d_doutとかd_dxで書いた。
この認識でどうなんだろうか。
あんまりDeepLearningの実装の中身をいじる可能性はないかもしれないが、もしあったら気にしてみたい。

class Sigmoid:
    def __init__(self):
        self.out = None
    
    def forward(self, x):
        self.out = 1 / (1 + np.exp(-x))
        return self.out
    
    def backward(self, d_dout):
        d_dx = d_dout * self.out * (1 - self.out)
        return d_dx

各種レイヤの実装

計算グラフでの表現ということで、"レイヤー"として演算を実装していた。
ニューラルネットワークだと、入力→演算→その出力を別の演算にかける…を繰り返していくので、確かにそれが自然なのかと理解したと思う。

買い物の計算の例で使った乗算レイヤ、加算レイヤといった単純なものから、実際にニューラルネットワークで使うReLU、Sigmoid、Affine、Softmax-with-Lossレイヤというのも解説されていた。
Sigmoidまでなら理解できたが、残り2つがよく分からん…

Affineはベクトル、行列になったときの扱いが難しい…

入力データとしてバッチを使う場合の対応も書かれていたが、なぜそれでいいかもいまいち理解できず。

ひとまず、こんなレイヤがある、で、入出力やforward()backward()関数がどんなことをやってる、の認識までで。

  • 乗算レイヤ:
    • 2入力1出力
    • 微分を求めるとき、そのときの入力値も知っていないといけないので、forward()関数実行のときにクラス変数で覚えておく
    • backward()では、各入力に対する出力の変化具合があるので、2つ出力が出る
  • 加算レイヤ:
    • 乗算と同じく2入力1出力
    • 入力変化がダイレクトに出力に出てくるので、forward()で今の入力値を覚える必要はなく、backward()ではd_doutをそのまま2つ出力する
  • ReLU, Sigmoid:
    • どちらもn入力n出力 (1つの入力に対して1つの出力)
    • 入力そのままでなくても、出力結果や入力をちょっといじったものだけ覚えておけば微分が分かるので、そういうのをforward()で覚えておく
    • backward()では、各入力についての出力の微分を返す
  • Affine:
    • 入力は、単一データなら(2,)の形状、バッチなら(n,2)の形状で、出力の形状はそれぞれ(3, )、(n, 3)
    • という形で書かれてるが、入力ベクトルの長さ2、出力ベクトルの長さ3は一般化して考えてコード実装されてる
    • (2,3)の形状の重み、(3,)の形状のバイアス項を内部で持つ
    • 入力 X、重み W bについての微分backward()で計算しているが、返り値としては Xについての微分だけ返してる。 W bについては内部で微分値を保持して、最後に取り出ししてる。
  • Softmax-with-Loss:
    • 入力は、単一データなら(m,)の形状、バッチなら(n, m)、出力はどの場合も1つの値だけ (mは、MNISTの手書き文字認識なら0~9の10パターン)
    • 誤差逆伝播法はここからスタートな感じ
    • ここでの損失関数に対する入力の影響具合は、入力をsoftmax関数で0~1に正規化した値と正解ラベル t_i (0 or 1)の差で計算されて、最終的な間違いが大きいほど微分、勾配が大きく出る

ネットワークでの誤差逆伝播法の実装

レイヤーを定義して、そのレイヤーの重ね合わせでネットワークでの演算を実現する。
各レイヤー、現在の入力値の情報を得ないといけないので、まず一度入力を決めて、forward()を全レイヤー呼ぶ。

その後、backward()関数を後ろから順々にやっていって、最終的にネットワークの重みによる目的関数の微分、まで落としていく、その結果を勾配として返す。

という手順。

実際に世の中で使われているフレームワークだとどうなってるかは分からないが、この辺りを理解しておけば理解できるか?

以上

今回は内容難しかったが、必要そうなことだけ一旦理解して、次に進めていく。