頭と尻尾はくれてやる!

iOSアプリなどの開発日記です


Metal Performance Shaderで同期処理っぽく記述する

機械学習などでMetal Performance Shaderを使ってNNの計算をする時、GPUに渡してそれが終わったら結果が得られるようになるって流れなので、コードの見通しが悪くなる。

a = [self inference:s];

ってな感じで記述できればいいんだけど、実際は

[self inference:s];

ってしといて結果が出た後の処理は別なところに書かないといけない↓
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
    //続きはこんなところ!
}];
なんとかならないのかなあと思ったらsemaphoreなる仕組みがある。

Objective-Cで非同期処理を同期処理にする方法。 | 三度の飯とエレクトロン

↑これを参考にてコードを書き直してみたところ、、、

a = [self inference:s];

という感じの記述ができて意図通り動いた!
計算に時間がかかるとまずい場合もあるかもしれないが、今やってることに対しては計算時間も短く問題なさそう。


コードはざっくりこんな感じ。勝手な構造体なんかは気にしないで。
-(MPSResult_t)inferenceForInputs:(Inputs_t)inputs
{
    __block MPSResult_t mpsResult;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        
        [self->srcImage.texture replaceRegion:self->srcImageRegion
                            mipmapLevel:0
                                  slice:0
                                    withBytes:self->angles
                            bytesPerRow:sizeof(float)*4
                          bytesPerImage:0];
        
        @autoreleasepool{
            id <MTLCommandBuffer> commandBuffer = [self->commandQueue commandBuffer];
            
            [self->h1 encodeToCommandBuffer:commandBuffer sourceImage:self->srcImage destinationImage:self->h1Image];
            [self->h2 encodeToCommandBuffer:commandBuffer sourceImage:self->h1Image destinationImage:self->finalImage];
            
            [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
                
                [self->finalImage.texture getBytes:&self->qResults[0]
                                 bytesPerRow:sizeof(float)*4
                                        fromRegion:self->filnalImageRegion
                                 mipmapLevel:0];
                
                mpsResult.q0 = self->qResults[0];
                mpsResult.q1 = self->qResults[1];
                
                dispatch_semaphore_signal(semaphore);//止めてたのを終える
                
            }];
            
            [commandBuffer commit];
        }
    });
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//これで止める
    
    return mpsResult;//結果が出てからリターンする
}
スポンサーサイト






コストコでクロスバイクを買った

コストコのクロスバイクってどうなのよ?というのは専門家でもなんでもないのでよくわからない。
ただ、ロードバイク・クロスバイクを売ってるような専門店にある自転車からすると、、、とにかく安い。

コストコのクロスバイク(eisan)

↑税込で19,980円だった。3x7段変速。なかなかかっこいいんじゃね?!
一度決心して買いに行ったら売り切れだったんだが、1週間後くらいに電話で在庫確認したら「ある」とのことですぐに行き買うことができた。コストコの店員さん、ありがとう!

車に入れた自転車

↑コストコは配達してくれないので車に詰め込んで、近所の自転車屋(イオンバイク)で防犯登録(600円)と初期セッティング(1,620円)をしてもらった。
しかし、どういうわけか一番重いギアに入らない。よく見ると手元にあるギアを示す1から7の数字と実際のが合っていない。手元が7だと6段目に入り、手元が1だと1より低い側、それこそ”0”あたりへ行こうとする。
他店で買った自転車だから嫌がらせされたんだろうか?
すぐにお店に戻って言うと別な人が調整してくれたんだが、ディレイラーにある二つの調整用ネジをいじって対応してた。

リアディレイラーの調整用ネジ

↑ワイヤーとかいじらんでええんか?ネジがえらい飛び出てるで?

まあ、とりあえず1から7速まで入るようにはなった。


乗ってみて気になったことをいくつか。

フロントの方はギアは3枚だけど、手元での変速は何段か知らないけど細かく動かすことができる。そんなこともあって、例えば1速で漕ぎ始めたころには静かでもギアを上げて行くとどこかでフロントディレイラーとチェーンがカチカチと当たって音がすることがある。フロント側を調整すると静かになるんだけど、、、地味にめんどくさい。しかもフロント(左手)ってどっちに回転させればどうなるのかまだ慣れてない。

スタンドが最初から付いてるのはありがたいんだけど、スタンドの出っ張ったとこに左足のかかとが引っかかることが時々ある。スタンドを買い換えたいくらい。

乗り心地は、、、比べるものがないけどママチャリよりは路面の凸凹を拾う感じがする。走りやすい道路とそうでない道路の好みができる。近所にサイクリングロードがあればなあとか思う。

「弱虫ペダル」にもあったけど、サドルの高さはちゃんと合わせよう。楽しさ倍増する。
買って後悔はない、今のところ。



↑なお、仏式の空気入れはAmazonで購入。仏式って初めてだったが、ちゃんとこれで空気を入れることはできてる。なお最大空気圧はタイヤに書いてた。







Macで一太郎のjtdファイルを見る

町内会関連で引き継いだUSBメモリ内に拡張子がjtdのファイルがあってなんだ?と思ったら一太郎のファイルらしい。
なんとかMacで見られないものか(編集はできなくてもいいから)と調べるとこんな記事が↓

Mac上でWindowsのアプリを動かしてみよう!(Boot Campは使いたくない人必見!) | アップル大好きmaroのブログ

これを参考にPlay on Macをダウンロード(妙に時間がかかった)。
XQuartzもインストール。他にもいろいろあったが指示通り。
一太郎ビューアも公式からダウンロード。

すんなりとインストールできたわけじゃないけど、もがいてたらやっと起動した。

Play on Mac
↑ここで一太郎ビューア2014を選択し、実行すると、、、

Wineエクスプローラ

↑Wine エクスプローラなるものが起動し、目当てのjtdファイルを選択すれば見ることができた!



(備考)
High Sierra 10.13.4
Play on Mac 4.2.12
一太郎ビューア 24.0.1.0


SCNPhysicsHingeJointで謎の誤差

SceneKitで作る振り子

↑SceneKitでこういう振り子を作るのに、振り子のオブジェクト(ここでは直方体)を空間にSCNPhysicsHingeJointで固定している(横の支柱は今回は物理演算には関係のない飾り)。

この時のコードはこんな感じ↓
{
        SCNVector3 xAxis = SCNVector3Make(1.0 , 0.0 , 0.0);
        SCNVector3 anchor = SCNVector3Make(0.0, pendulumHeight/2.0, 0.0);
        SCNPhysicsHingeJoint *hingeJoint = [SCNPhysicsHingeJoint jointWithBody:pendulumNode.physicsBody axis:xAxis anchor:anchor];
        [mainScene.physicsWorld addBehavior:hingeJoint];
}
これでx軸方向のベクトルを中心に回転するjointが設定できる。振り子にトルクをかければちゃんと振り子のように動く。
ここまではいいんだけど、この時振り子の位置を確認すると、なんだかよくわからない誤差がある。

SCNNodeオブジェクトの位置・姿勢が取得できない
なおこういう場合、位置は↑のように pendulumNode.presentationNode から得る。

上のコードで pendulumHeight=2.0 、回転軸の高さがy=0なら初期の静止した状態の高さyは-1.0のはずが -1.014 とかになってしまう???

なんや、その誤差は?

振り子の付け根部分のずれ

↑本来なら棒の端と板の端は同じのはずが、確かにずれてる。

以前使ってたBulletという物理エンジンのことを思い出すと、まあこういうジョイント部分もオブジェクト同士(今回はオブジェクトと空間だけど)がかっちりくっついてるかというとそうでもなく、力をかければちょっとは離れる、といった計算になることも多分ある気がする。
もしかしてSCNPhysicsHingeJointに”固さ”というかそういうパラメータがあるのかな、と思ったけどリファレンスを見る限りなさそう。
オブジェクトの重さで重力方向に下がってしまっているのか?と思い質量を変えてみたけど、この値に変化はなし。
うーん、なんだろうなと思って重力加速度をゼロにしたら誤差はなくなった!
よくわからないけど、なんかそういう仕様になっているようだ。

深く考えるのはよそう、だってSceneKitだもの(みつを)。


SCNNodeオブジェクトの位置・姿勢が取得できない

倒立振子

↑強化学習やってみようかな、と思ってSceneKitでこういう振り子を作ったんだ。いわゆる倒立振子をやろうとしてる。”とうりつしんし”と読むとかどこかで見た気がするが真偽不明。

最初はクリックなりを検出して振り子にトルクを与えて、、、てな感じで動作確認してたんだけど、動いている振り子の位置、姿勢が取得できない、という状況にはまった。
SCNNodeオブジェクトをnodeとすればその位置、姿勢は
node.position
node.orientation
で取得できるやん?
それが振り子をいくら動かしても値が変化しないのよ。

scenekit - Getting an SCNPhysicsVehicle's Position - Stack Overflow

↑いろいろ調べてようやくたどり着いたのがこちら。
確かに presentationNode を使うといけた。
物理エンジンを使った場合にはそういうことらしい。


  TopPage  



Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.