M1 OS 12.4 に Miniconda で Pytorch と Tensorflow をインストールする

概要

Apple M1 Pro, Macbook Pro で、Anaconda をアンイストールし、Miniconda をインストール、

  • Pytorch
  • Tensorflow

をインストールする。

特に Tensorflow のインストールでトラブルが多いため様々な情報があるが、私の環境でのインストールを書きます。

tensorflow はパッケージの バージョンの組み合わせによっては動作しないパターンが有る ということ(要約するとこれが今回の記事のポイントです)。

ご参考まで。

環境

  • Macbook Pro 14 inch
  • Apple M1 Pro
  • OS 12.4 (Monterey)
  • Anaconda インストール済み

今まで特に Deep Learning を使わずに分析や機械学習等やってきましたが、画像を扱う案件があり、データセキュリティ上ローカルでの構築が必要で環境を作り直しました。

Anaconda のアンイストール

$ conda install -c anaconda anaconda-clean
$ anaconda-clean
Delete .conda? (y/n): y
Delete .ipython? (y/n): y
Delete .jupyter? (y/n): y
...

$ rm -rf ~/opt/anaconda3

参考にしたサイト qiita.com

Miniconda のインストール

Pytorch のサイトを参考にした。

$ curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh
$ sh Miniconda3-latest-MacOSX-arm64.sh

pytorch.org

Miniconda では環境を作ったときに python さえもインストールされないミニマル環境なのでビビりました。

$ conda create -n my_new_env

Pytorch のインストール

上記の Pytorch サイトを参照し

$ conda install pytorch torchvision -c pytorch

$ ipython 
In [2]: import torch
In [3]: x = torch.rand(5, 3)
In [4]: print(x)

Tensorflow のインストール

トラブル多し。ポイントは、

  • tensorflow-deps
  • tensorflow-macos
  • tensorflow-metal

バージョンの組み合わせによっては動作しないパターンが有るということ(これが今回の記事のポイントです)。

developer.apple.com

私の環境では次のバージョンの組み合わせで動作した。

$ conda install -c apple tensorflow-deps==2.10.0
$ python -m pip install tensorflow-macos==2.10.0 tensorflow-metal==0.6.0

$ ipython
In [2]: import tensorflow as tf
In [3]: tf.__version__
Out[3]: '2.10.0'

OS 13.1 の人も上記フォーラムでは

tensorflow-deps 2.10, tensorflow-macos 2.10 and tensorflow-metal 0.6.0

の組み合わせでうまく行ったとのこと。

一方、OS 12.4 では下記の組み合わせでもうまくいったという報告があります。

tensorflow-deps 2.9, tensorflow-macos 2.9 and tensorflow-metal 0.6.0

OpenCV 4.6.0 AttributeError: module 'cv2' has no attribute 'CascadeClassifier'

OpenCV 4.6.0.66 で次のエラーが発生した。

In [4]: cv2.CascadeClassifier()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 cv2.CascadeClassifier()

AttributeError: module 'cv2' has no attribute 'CascadeClassifier'

正直なところ原因はわからないのだけれど OpenCV の version をダウングレードしたら発生しなくなったので、python などとの相性が関係している模様。

opencv==4.6.0.66

conda install -c conda-forge opencv==4.6.0

とした。

ちなみに python==3.10.5, conda 4.13.0

根本的な解決方法ではないが、ここで躓いて先に進めないことも機会損失かと思い、書いておきます。

TINY2040(Raspberry Pi Pico) と Arducam Mini 2MP Plus(OV2640 SPI Camera) を接続する

前回同様、今度は TINY2040 に Arducam Mini 2MP Plus を接続し、BMP 画像をキャプチャしました。

www.arducam.com

TINY2040 は Pimoroni が出している、Raspberry Pi Pico と同じチップを用いた切手サイズのボードです。 とはいえ、Raspberry Pi Pico と Tiny 2040 は外に出されているピンが一部異なります。

Tiny2040
Tiny 2040shop.pimoroni.com

さて、 Tiny 2040 に Arducam Mini 2MP を接続する際、Raspberry Pi Pico での配線は前回のとおりですが、Tiny 2040 は配線として出されているピンが異なるため一部を別のピンに接続する必要があります。
Raspberry Pi Pico と Tiny2040 の Arducam Mini 2MP Plus 接続ピンの比較は次です。

つまり、コントロール信号用の I2C ピンが異なります。従って Arducam から提供されている SDK のピン配置を変更すれば良いことになります。
SDK では ArduCAM.h L.341 あたりにピンアサインの定義がされています。

/*i2c pin source */
#define I2C_PORT i2c0
#define PIN_SDA  8
#define PIN_SCL  9

ここを、TINY2040 用に変更することで事足ります。

/*i2c pin source */
#define I2C_PORT i2c1
#define PIN_SDA  6
#define PIN_SCL  7

Preprocessor 等でスイッチする際は C/Examples/CMakeLists.txt に記載するなど、ビルドオプションとするのが良いでしょう。

add_compile_definitions(TINY_2040)

参考までに接続図も載せておきます。(GND, VCC はどこかに適切に接続してください)

Tiny2040

PICO の接続図と動作の確認は、前回ご紹介した簡易の BMP キャプチャ jupyter でできます。 entre-temps.hatenablog.com

OSX で Raspberry Pi Pico / Arducam Mini 2MP Plus(OV2640 SPI Camera) から BMP 画像をキャプチャする

久々にこのあたりを触っており、上記タイトルのことをやってみたので投稿します。
Mac ユーザーは Arducam の画像キャプチャアプリを使えないので不便です。
python で簡単な確認スクリプトを作って BMP を確認してみました。
ちなみに、Arducam Mini 2MP Plus(OV2640 SPI Camera) はすでにディスコンのようで今後のことを考えるとあまり意味がないかもしれませんので、参考程度に。 www.arducam.com

配線はこちらです
https://www.arducam.com/wp-content/uploads/2021/07/%E8%BF%9E%E7%BA%BF%E5%9B%BE.png

PICO_SPI_CAM/C/Examples/Arducam_MINI_2MP_Plus_Videostreaing/ をベースに変えていきます。 github.com

変更内容は以下の diff のとおりです。 CMakeLists.txt を変更するのを忘れないでください。

sdiff -s Arducam_MINI_2MP_Plus_Videostreaing/Arducam_MINI_2MP_Plus_Videostreaing.cpp Arducam_MINI_2MP_Plus_Videostreaming_BMP/Arducam_MINI_2MP_Plus_Videostreaming_BMP.cpp
  tusb_init();                                                |   //tusb_init();
                                                              >
                                                              >   // システムが起動仕切るのに時間がかかっている
                                                              >   sleep_ms(2000);
                                                              >
         //Change to JPEG capture mode and initialize the OV5 |         //Change to JPEG capture mode and initialize the OV56
  myCAM.set_format(JPEG);                                     |   /* myCAM.set_format(JPEG); */
                                                              >   /* myCAM.InitCAM(); */
                                                              >   /* myCAM.OV2640_set_JPEG_size(OV2640_320x240); */
                                                              >
                                                              >   // JPEG 設定で後で BMP に変えると、変な設定が残る(カラーピクセ
                                                              >   // (ArduCAM::InitCAM() あたりの initial 設定)
                                                              >   myCAM.set_format(BMP);
  myCAM.OV2640_set_JPEG_size(OV2640_320x240);                 |
        symbol[0]=0xff;                                       |         /* ビューワーアプリ側の仕様か BMP body の前後に 0xff 0xaa
        symbol[1]=0xaa;                                       |         /* symbol[0]=0xff; */
                                                              >         /* symbol[1]=0xaa; */
        SerialUsb(symbol, sizeof(symbol));                    |         /* SerialUsb(symbol, sizeof(symbol)); */
        symbol[0]=0xbb;                                       |         /* ビューワーアプリ側の仕様か BMP body の前後に 0xff 0xaa
        symbol[1]=0xcc;                                       |         /* symbol[0]=0xbb; */
        SerialUsb(symbol, sizeof(symbol));                    |         /* symbol[1]=0xcc; */
                                                              >         /* SerialUsb(symbol, sizeof(symbol)); */
}                                                             \ }

Python 側の受けはこちらで jupyter lab で組みました。取れた画像もつけておきます。

# serial communication with ARDUCAM
import serial
import array
import time
from PIL import Image
import numpy as np
from matplotlib import pylab as plt

'''
%ls /dev/tty.*
/dev/tty.Bluetooth-Incoming-Port  /dev/tty.usbmodem101
'''
COM = '/dev/tty.usbmodem101'

ser = serial.Serial(COM, 115200)
print(ser)
'''
Serial<id=0x7fcf800c5ae0, open=True>(port='/dev/tty.usbmodem101', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
True
'''

# timeout 1000msec
def rcv():
    for i in range(100):
        b_rep = ser.read_all()
        if len(b_rep) > 0:
            print(b_rep)
        time.sleep(0.01)
        
def snd_cmd(cmd):
    ser.write(cmd)
    ser.flush()
    rcv()
    
# Single shot - timeout 10sec
def single_shot_bmp():
    
    # single shot command
    ser.write(bytes([0x30]))
    ser.flush()
    
    resp = b""
    for i in range(10000):
        _resp = ser.read_all()
        if len(_resp) > 0:
            resp = b"".join([resp, _resp])
            if len(resp) >= 153737:
                break
        time.sleep(0.001)
        ser.flush()
    print(len(resp))
    
    return resp

# BMP 取得する

# 1. BMP にキャプチャフォーマットを変更
# Received 0x31(49)', b'ACK CMD SET FORMAT TO BMP.
snd_cmd(bytes([0x31]))

# 2. ワンショットキャプチャ - resp に全部入ってくる
resp = single_shot_bmp()

# 3. Response message に色々と入っているので、 BMP データ(Header 含む)はそれ以降のバイナリ配列
# b'Received 48ACK CMD CAM start single shoot. ENDACK CMD CAM Capture Done.'
print(resp[:71])

# (番外編)そのまま bmp にして保存すると色バランスがおかしい。
# カラーマスクがうまく働かないのかもしれない (ビューワー側の問題? - カラーマスクにしっかり対応したビューワーはあまりないとのこと)
pix = resp[71:]
with open('myfile2.bmp', 'wb') as f:
    f.write(pix)

'''
BMP HEADER なしで、カラーマスクを使って RGB を再現する
http://dencha.ojaru.jp/programs_07/pg_graphic_04.html

5-5-5
R 0x00007C00
G 0x000003E0
B 0x0000001F

5-6-5 ---> 今回はこっち
R 0x0000F800
G 0x000007E0
B 0x0000001F

色を取得するときは5-6-5なら
  R = (color & R_mask) >> 11;
  G = (color & G_mask) >> 5;
  B = (color & B_mask) >> 0;
'''

# BMP header をスキップし画素にアクセス
_pix = pix[66:]
print(len(_pix))

height = 240
width = 320
im = []
for h in range(0, height, 1):
    _im = []
    for w in range(0, width, 1):
        i = 2*(h*width+w)
        p = (_pix[i] << 8) | _pix[i+1] 
        r = (p & R_mask) >> 11
        g = (p & G_mask) >> 5
        b = (p & B_mask)
        _im.append((r<<3, g<<2, b<<3))
    im.append(_im)
plt.imshow(im)

HAL/S の COMPOOL はピンが最初から抜かれている手榴弾に例えられるべきだ

"C のポインタの危険性を剥き身のナイフに 例えるなら、HAL/S の COMPOOL はピンが最初から抜かれている手榴弾に例えられるべきだ"

"HAL/S は珍しい、死亡日時がはっきりしたプログラミング言語となる。STS-135 向けのミッショ ン用コード差分の最後のものが書かれた瞬間に、HAL/S の死は確定する。命日は 2011 年 7 月 21 日、 最後のシャトル OV-104 アトランティス搭載の AP-101S から火が落とされる瞬間だった。これより 先、HAL/S でコードが記述されることは二度と無いだろう。"

<本文より> http://www2a.biglobe.ne.jp/~mizuki/tmp/programming_HAL_S_V2a.pdf

序: プログラミング言語に優务は無い、と言う人がいる。 それは今日の、素晴らしい言語が綺羅星のように並び立つ現状に慣れた、恵まれた立場からの発 言である。残念ながらプログラミング言語に優务は存在する。あまりの酷さに頭をかきむしり、製 作者の正気を疑う、そういう言語は存在する。所詮、人が作るものなのだから。 プログラミング言語は決して、チューリング完全を獲得次第速やかにユーザフレンドリーになっ たり、記述の簡潔さを自律的に獲得したりはしない。それらは創造者が与えるものなのだ。 本書では、残念ながら優れた言語とならなかった例として、ひとつのプログラミング言語を紹介 する。

HAL/S は珍しい、死亡日時がはっきりしたプログラミング言語となる。STS-135 向けのミッション用コード差分の最後のものが書かれた瞬間に、HAL/S の死は確定する。命日は 2011 年 7 月 21 日、最後のシャトル OV-104 アトランティス搭載の AP-101S から火が落とされる瞬間だった。これより先、HAL/S でコードが記述されることは二度と無いだろう。

.

.

.

水城徹さんがこれを執筆されてから、丁度 10 年が経過して、数多のソフトウェア言語が生まれそして設計自体も洗練されてきました。 今、私は機械学習モデルの実運用化に関っていて、当時と全く異なる状況ではありますが、改めてこのテキストを読んでいます。

f:id:entre_temps:20210620134035p:plain

(上記の記事より引用させていただきました)

branch not equal

実はこのブログは昔から少しずつ書いていたブログを引き継いでいたりします。

ちょっとイキった名前をつけたブログでしたが、当時は non-OS から rt-OS、embeded-Linux など組み込みシステム、それだけでなく Verilog-HDL や VHDL でデジタル回路も組んでいました。

そのためだいぶ低レイヤーの視点で、また今の世の中からしたら価値のない情報ばかりですので、一新した(つもり)のです。

そこからいくつか、今でも面白なと思うものを転載しようと思います(とはいえ、ほぼ無いですが)。

SuperCollider を Emacs で使う(Scel)

概要

ここ最近、だいぶ久しぶりに SuperCollider や Max を再開し、過去のコードを眺めたり紐解いたりしている(昔は PowerPC だったし、Max/Msp 4 だった)。 今は OSC などアプリケーション間通信プロトコルも整備されているし、Processing や Ableton Max for Live など他のアプリケーションとの連携も容易になってきている。 自分にとっては手慣れた Python が FoxDot のような形で使えるようになってきているのも嬉しい。 何より、Python にも librosa などサウンドプロセッシングのライブラリがあるし、Machine Learning など広大な世界が広がっている。

このような背景で再度始めたわけですが、やはり手慣れたツールでやりたいので EmacsSupercollider を使う環境を準備しました。 その方法を備忘含め記します。

手順

  1. Scel をダウンロード(thanx!)
  2. sclang**.el を .emacs/site-lisp に配置
  3. HelpSource と sc を /Users/<ユーザー名>/Library/Application Support/SuperCollider/Extensions/scide_scel に配置
  4. init.el に path と require を追加
(dolist (dir (list
              "/sbin"
              "/usr/sbin"
              ...
              "~/Applications/SuperCollider/SuperCollider.app/Contents/MacOS"
))

(require 'sclang)

私はこれにショートカットを足しています。

(defun my-sclang-mode-init ()
  (local-set-key "\C-c\C-b" 'sclang-server-boot)
  )
(add-hook 'sclang-mode-hook 'my-sclang-mode-init)

参考までに最後にデフォルトのキーマップやコマンドを載せておきます。

使い方

Supercollider は起動しておく必要はありません。 Emacs から sclang-start で起動します。

M-x sclang-start
compiling class library...
    Found 850 primitives.
    Compiling directory '/Users/<ユーザー名>/Applications/SuperCollider/SuperCollider.app/Contents/Resources/SCClassLibrary'
    Compiling directory '/Users/<ユーザー名>/Library/Application Support/SuperCollider/Extensions'
    Compiling directory '/Users/<ユーザー名>/Library/Application Support/SuperCollider/downloaded-quarks/BatLib'
    Compiling directory '/Users/<ユーザー名>/Library/Application Support/SuperCollider/downloaded-quarks/FoxDot'
    numentries = 1272073 / 19323360 = 0.066
    5751 method selectors, 3360 classes
    method table size 20776064 bytes, big table size 154586880
    Number of Symbols 14863
    Byte Code Size 438094
    compiled 563 files in 1.63 seconds
compile done
localhost : setting clientID to 0.
internal : setting clientID to 0.
Emacs: Initializing lisp interface.
Class tree inited in 0.02 seconds


*** Welcome to SuperCollider 3.11.0. *** For help type C-c C-y.
Emacs: Index help topics in 0.445 seconds
Emacs: Built symbol table in 0.0247 seconds

忘れずに server を boot して

M-x sclang-server-boot
server 'localhost' unresponsive, rebooting ...
'/quit' message sent to server 'localhost'.
Booting server 'localhost' on address 127.0.0.1:57110.
Found 0 LADSPA plugins
Number of Devices: 5
   0 : "外部"
   1 : "外部"
   2 : "MacBook Airの"
   3 : "MacBook Airのス"
   4 : "ZoomAudioD"

"外部" Input Device
   Streams: 1
      0  channels 1

"外部" Output Device
   Streams: 1
      0  channels 2

SC_AudioDriver: sample rate = 44100.000000, driver's block size = 512
SuperCollider 3 server ready.
Requested notification messages from server 'localhost'
localhost: server process's maxLogins (1) matches with my options.
localhost: keeping clientID (0) as confirmed by server process.
Shared memory server interface initialized

これで準備は OK です。 試しに SuperCollider Workspace (scratch のようなインタラクション用のサンドボックス) にこれを打ち込み、実行します。

{ LFSaw.ar([160, 160 + 12.midicps], 0, 0.2) }.plot(0.1);
M-x sclang-eval-region-or-line

ちゃんとプロットもされます。

f:id:entre_temps:20210620104057p:plain
scel

最後に

コマンドはこれくらいあるので、ほぼ開発する上においては不自由しないでしょう。何より Emacs が使えるのが私は嬉しいと思っています。いつもながら、開発してくれている方々に感謝です。

Possible completions are:
sclang-beginning-of-defun 
sclang-browser-beginning-of-link 
sclang-browser-follow-link 
sclang-browser-mode 
sclang-browser-mouse-follow-link 
sclang-browser-next-link
sclang-browser-previous-link 
sclang-browser-quit 
sclang-class-tree 
sclang-clear-post-buffer 
sclang-complete-symbol 
sclang-customize
sclang-dump-full-interface 
sclang-dump-interface 
sclang-edit-dev-source 
sclang-edit-help-code 
sclang-edit-help-file 
sclang-edit-html-help-file
sclang-electric-brace 
sclang-electric-slash 
sclang-electric-star 
sclang-end-of-defun 
sclang-eval-defun 
sclang-eval-document
sclang-eval-expression 
sclang-eval-line 
sclang-eval-region 
sclang-eval-region-or-line 
sclang-find-definitions 
sclang-find-help
sclang-find-help-in-gui 
sclang-find-primitive 
sclang-find-references 
sclang-goto-help-browser 
sclang-help-minor-mode 
sclang-help-mode
sclang-help-mode-beginning-of-defun 
sclang-help-mode-end-of-defun 
sclang-index-help-topics 
sclang-kill 
sclang-main-run 
sclang-main-stop
sclang-minor-mode 
sclang-mode 
sclang-mouse-next-server 
sclang-next-server 
sclang-open-help-gui 
sclang-pop-definition-mark
sclang-recompile 
sclang-server-boot 
sclang-server-display-default 
sclang-server-dump-osc 
sclang-server-free-all 
sclang-server-make-default
sclang-server-pause-recording 
sclang-server-prepare-for-record 
sclang-server-quit 
sclang-server-reboot 
sclang-server-record 
sclang-server-stop-recording
sclang-set-server-latency 
sclang-show-method-args 
sclang-show-post-buffer 
sclang-show-server-latency 
sclang-show-server-panel 
sclang-start
sclang-stop 
sclang-switch-to-workspace 
sclang-toggle-debug-command-handler 
sclang-update-server-info

勘を取り戻したら FoxDot や Python や他のアプリケーションとの通信含め色々とトライしたいと思っています。