unable to launch "cinnamon-session-cinnamon" X session - 云々

タイトルのエラーを吐いて、突然、ロボット制御用に使っているLinux Mint (32ビット)が立ち上がらくなった。ネットには色々書かれているが、私の場合、次の方法で解決した。

(1)エラーメッセージが出ている状態で、Ctrl-Alt-F1でXウィンドウを使わないCUIモードに変更する。

(2)ログインする

(3) $ sudo apt-get install mint-meta-cinnamon を実行する

なぜ、こんなことになるのか、なぜこの方法で解消するのか、一切不明。

Hikey970のlebuntuに日本語環境を入れる

オリジナルなHikey970のubuntu、つまりlebuntuは全く日本語環境が入っていないので、前の記事ではubuntu18.04を入れるとか言っていたが、実はそれはとても難しく、私にはできそうになかった。

そこで、lebuntuに追加で日本語環境をインストールすることにした。フォントなどをインストールしたら、日本語は表示できるようになったし、localeをLANGでja_JP.UTF-8にしたら、出力が日本語になって使いやすくなった。

しかし、日本語の入力はいまだにできない。悩ましい。

Hikey970にUbuntu (Lebuntu) をインストールする

ニューラルネットワーク処理ユニット(NPU)を持つシングルボードコンピュータを、スイッチサイエンス社から39,744円で購入した。アマゾンに出ている商品と同じものだが、ここが一番安かった。

ひたすら好奇心である。NPUというものは、どれほどのものだろうということである。ただし、UPUをのぞいでも、このコンピュータのスペックはとてもいい。

まだ、NPUをどうやって動かすのか、というか、プログラミングに組み込むのかということはわかっていないが、さしあたり、試しに、Ubuntu、LemakerのUbuntuという意味で、Lebuntuというらしい、を組み込んでみた。

最終的には上記のようにlebuntuがスタートする。最大の弱点は、日本語環境が出てこないことだ。

インストールの仕方をメモがわりに記載する。
(1)Linux を用意する。
(2)このサイトから、lebuntuのimgファイル類をダウンロードする。
(3)rarファイルを解凍する。(ubuntuの場合、unrarが必要だった)
(4)その中に、lebuntu-rfs_flashing_guide.txtというドキュメントがあるので、そこに書いてある通りのことを実行すれば、インストールできる。その通り実行しないと失敗する!!
以下注意点
(1)INSTALLING BINARIES(only new boards)とFLASHING Lebuntu 16.04 IMAGE ONLYの二回実行する。
(2)Hikey970のUSB-CとLinuxのUSB端子をつなぐ。
(3)MACのVirtualBoxに入れたLinuxでやったら失敗した。USBのつながりがダメなようだ。Linuxマシンを用意する。私の場合は、Intelのスティックコンピュータに入れたUbuntuにつないで実行した。

特にないか。要は、先のマニュアル通りのことができればOKなのだ。

ただ、Lebuntuでは、日本語が使えない(使い方があるのかもしれないがわからない)ので、今度、正式のUbuntu 18.04をインストールしようと思う。

NPUは、Hikey970 with pre-built Tensorflowというのがあるので、そちらのimgを焼くことで実現するのだと思う。

MapになっているニュースのListを日付順にソートする

要は、MapのListをMapのあるValue順にソートするということだけれど、答えはこちらのサイトで教えていただきました。

Collections.sort(maplist, new Comparator<Map<String, String>>(){
    @Override
    public int compare(Map<String, String> rec1, Map<String, String> rec2) {
        String colName1 = rec1.get("pubDate");
        String colName2 = rec2.get("pubDate");
        return colName2.compareTo(colName1);
    }    
});

mariadbのデータフォルダ移動、シンボリックリンクが一番!

以前、スティックコンピュータで、mariadbのデータフォルダをmicroSDに移したという話を書いたが、その時は、my.cnfの設定を変更したものだった。今回、VPSのmariadbはそれでも簡単にいかなかったので、新しいフォルダ/data/mysqlに、/var/lib/mysqlからのシンボリックリンクを貼ってやってみた。難なく、それだけで、全て片付いた。これが一番楽チンだ。以下の方法は、CentOS用です。他は、コマンドが違うかも。

(1)mysql (mariadb) を止める ← 重要
(3)新しいフォルダを作成しオーナーを変更する
sudo chown mysql:mysql /data/mysql
(3)新しいフォルダーに全部コピーする
sudo cp -pr /var/lib/mysql/* /data/mysql/
(4)元のフォルダーをrenameして使えなくしておく(万が一のために元に戻せるように)
(5)シンボリックリンクを貼る
sudo ln -s /data/mysql/ /var/lib/mysql
とこうなる。
lrwxrwxrwx  1 root    root      12 11月 23 15:35 2018 mysql -> /data/mysql/
(6)mysql (mariadb)  を再スタートする

スティックコンピュータにミニディスプレイをつけた

ミニディスプレイをつけた。解像度は、高くても対応できるのだけれど字が小さくて見えなくなるので、800X600にしている。キーボードとマウスは、その両者ついているbluetoothのミニパッドがつながる。

あとは、sshを有効にして、パソコンからコントールできる。

Macのmariadbが動かなくなって

デスクトップMacのmariadbが

Can't read dir of '/usr/local/etc/my.cnf.d'

というエラーを吐いて動かなくなった。確かにそんなフォルダはない。え〜、突然!と思ったが、その前にtelnetをインストールするのにbrewをいじっていた。多分、

$ brew prune

コマンドなんかをやったからのように思うが、よくわからない。結局,

$ brew install mariadb

とやっても、すでに入っていますよと言われ、

$ brew update mariadb

で、バージョンアップしたら、治ってくれた。バージョンが最新だったらどうなったんだろうと思う。

JDeeplearningのプログラム概要(1)

https://github.com/toyowa/jautoencoder
で公開しているプログラムの覚書を書いておこうと思う。これから、ロボットのセンサーを増やす作業に入るので、どういうプログラムだったか忘れてしまいそうなので。この(1)では、全体的なことを書いておく。
1。データに関して
データのフォーマットは、
https://github.com/huangzehao/SimpleNeuralNetwork
のサイトのプログラムを参考にさせてもらった。(プログラムは、独立に私が自分で書いたものだ。プログラムは参考にするほど理解できなかったが、自分で書かないと使えないだろうと思ったから)
データの最初の1行は、
topology: 784 400 10
のようにネットワーク構造を書く。ここで、784が入力レイヤーのニューロン数。以下出力ユニットまで、にゅう論数を書いていく。レイヤーの数にもニューロン数にも制限はない。
その後に続いて、in:とout:の接頭語に続いて、交互に、入力データと出力データを空白を区切って書いていく。
MNISTの手書き数字データに関しては、データの読み取りは、
http://nonbiri-tereka.hatenablog.com/entry/2014/09/18/100439
を参考にさせていただいて、それを上記のデータフォーマットに書き直したものだ。
https://github.com/toyowa/jautoencoder/tree/master/MNIST
に変換用のプログラムをおいてある。
データプログラムは、実行時オプション -dataで指定できる。
2。ウェイトファイル
学習後にウェイトデータを吐き出し、テストの時はそのファイルを実行時オプション -weights で指定して読み込むことになる。ただし、ウェイトファイル名は、wgtのさフィックスがないと拒否するようにしている。データと間違わないように。データのさフィックスは特にチェックせずに読み込む。
吐き出されたウェイトファイル名には、そのファイルが作成された日時が秒までつくので、識別できると思う。ウェイトファイルの頭の部分に、その学習のネットワーク構造やパラメータや、繰り返し数などが書かれている。
-------------------
File name: [ weight_170603192205.wgt ]
Iteration: 179997
InputData: trainingData.txt
Topology: 784 300 150 10
Adjusting: 0.15
Label: Pre_neuron No. ->  Layer No. : Neuron No. = Weight
Weight: 0 -> 1 : 0 =    0.0003876341
Weight: 1 -> 1 : 0 =    0.0011203298
Weight: 2 -> 1 : 0 =    0.0004425993
Weight: 3 -> 1 : 0 =    0.0007930749
...........
...........
---------------------------------
なお、テストじゃない時にウェイトファイルを指定すると、そのウェイトを読み込んで、そこに書かれているそれまでの学習の実行の続きをやることになる。何回かに分けてやりたいとか、中間状態を見たい時には、そのような方法もできる。プログラムのデバッグの時は、一回だけ学習させるということもやった。実行時ぷションの、-maxiterで1を指定すると一回だけやる。
なお、-maxiterを指定しないと、データがある限り学習を続ける。
3。テスト
テストの時は、できたウェイトファイルとテスト用データの両方を実行時オプションで指定して、-test オプションを付け加えれば良い。当たり前だが、ウェイトファイルとテスト用データは、ネットワーク構造に関して整合的でなければならない。-weightsでウェイトを指定しないと、当然だが、ランダムに与えたウェイトでテストしてしまうので、テストは無意味だ。チェックして排除するようにすべきだったかもしれない。テスト結果はコンソールに出力される。
4。オートエンコーダー(Autoencoder):深層学習
実行時オプションで -auto をつけると、オートエンコーダーとバックプロパゲーションで学習する。オートエンコーダーとは、隠れ層へのウェイトを1層ずつ、一つの圧縮符号化器のように作っていくことだ。例えば、MNISTで、入力784ニューロン、300と150の隠れ層、出力層が10ニューロンだとしよう。それぞれのレイヤー(層)にA,B,C,Dという名前をつけよう。
まず、ABにA'というAと同じニューロン数のレイヤーをつけて、A'の学習データとして、Aと同じものを使うという作業をする。そして、ウェイトをバックプロパゲーションで形成するという作業をする。一見無意味なようだが、よく考えてみると重要な意味を持っている。AがA'で再現されるんだが、BはAよりもニューロン数が少ない。それが再現されるということは、Bの出力は、Aから入力されるデータの特色をすでになんらかの形で組み込んでいるということである。つまり、ニュー力データだけで、すでに学習してしまっているのである。これでAからBへのウェイトをまず作る。次にそこで最終的に得た出力を利用して、BCB'というネットワークを作成し、その先のネットワーク出力で、自己学習させるのである。Bの入力と、学習用のB'のデータはまた同じである。もちろんニューロン数も同じである。そうすると、BC間のウェイトがまたCで特徴が凝縮されるように形成される。最終的にこのようにできたAB間のウェイトBC間のウェイトを使って、元のABCDのネットワークを元々の学習用出力で学習させる。この時,CD間のウェイトは、私の場合、ランダムに作成したものにしているが、正解かどうかの確信はない。でも多分正しいだろう。これが、オートエンコーダーである。
少なくとも、MNISTのデータについては、うまく機能している。
-autoを指定すると、元のネットワークトポロジーが、5層でもそれ以上でも、同じようにやってくれる。試してないが、はずである。

C++とJAVA

本当に、JAVAの速さに驚いた動揺は未だに冷めない。784X300X150X10のネットワークをサクサクと学習する。ウェイトが、784X300+300X150+150*10=281700個ある。この順方向の計算と誤差逆伝搬によるウェイトの修正を一つのデータに関して行うのにかかる時間は1.67ミリ秒なのである。つまり、60000個のデータを約100秒で修正し終えるので、1サイクル28万個のウェイトを使った一個のデータの計算と修正には、0.00167秒、つまり、1.67ミリ秒しかかからないのである。
本来、JAVAに乗り換えたのは、スレッドの並列計算を導入しやすくする目的だったが、今の所、必要ないので1スレッドで動かしている。いずれ、使用スレッドを指定できるようにするつもりだ。
それはそうと、書いておきたかったのは、JAVAにして改めて、C++の違いに「えっ!」と気づいたことがあったからだ。C++とJAVAは、とてもよく似ていて、書き換えはスムーズにできる。今回、やってみて、クラスを配列に入れた時の振る舞いが違う。
例えば、仮にNeuronというクラスを作成して、この複数のインスタンス(オブジェクトというべきか)を配列neuronsに入れるとしよう。
C++の場合は、vectorを使って、インスタンス neuronを
vector<Neuron> neurons;
neuron.push_back(neuron);
としてvector配列に入れる。
この配列から、
Neuron neuron = neurons.at(1);
という感じで取り出して、このneuronの何かのメンバー変数の値を変更したら、
neuron.at(1) = neuron;
として戻してやらなければ、配列の中に保持されているインスタンスのメンバー変数の値は変わらない。
しかし、JAVAはクラス配列のインスタンスを取り出して、その値を変更すると、元の配列の中のインスタンスそのものの値も変更されているのだ。
だから、埋め戻しが不要だ。
C++愛好家とJAVA愛好家との間では、参照渡しなのか値渡しなのかがよく議論になるが、それと同じようなことだ。もちろん、JAVAのような仕様の方が助かる。なんだから、時間ロスも少ないような気がする。