さて、データセンター建設も大詰め。機器の搬入が終わりました。

DSCN6647.JPGもう少し広さに余裕あるかなぁと思ってたんですが、案外いっぱいいっぱいです。

写真の左手がストレージラック、正面がサーバラックです。

サーバラックの上にネットワークを入れてます。

DSCN6648.JPGストレージラックはこんな感じ。全部 QNAP です。QNAP だらけなので、19インチラックが使えません。

DSCN6649.JPGつぎにサーバラック。タワーサーバが多いので、やっぱり19インチラックは使えません。写真の一番下はLTOテープライブラリです。

DSCN6652.JPG最後にネットワーク。なんでこんなにあるんだ?って気もしますが。あと、なんでデータセンタに無線APがあるんだよ?!って突っ込みたくなりますが、便利だからです!


さーて、最後にかかった費用を計算してみましょう。

イナバ物置 230,000
エアコン 40,000
基礎工事部材 20,000
電気工事部材 80,000
ラック関連 70,000
ケーブル類 30,000
その他 10,000
合計 480,000

50万円で納まりました。当初の目標を達成です

今流行りのUTM、Fortigateを使ってみようかなと。

で、UTM である以前にルータであり Firewall なわけですから、PPPoE 接続するわけです。サーバとかある環境なんですから、固定アドレスは1個とか言わず、8アドレスサービスとか使いたいわけですよ。

となると、Unnumberd PPP を設定せなアカンわけですね。

そいでまって、ルータとなると、OSPF しゃべらせて、Default router として動作させないといけないわけです。

ちうわけで、Unnumberd PPP で OSPF を動かす設定。

config system interface
    edit "wan1"
        set vdom "root"
        set mode pppoe
        set ipunnumbered **.**.**.**
        set username "***"
        set pppoe-unnumbered-negotiate disable
        set password ENC ***
    next
    edit "vlan-gbl"
        set vdom "root"
        set ip **.**.**.** 255.255.255.**
        set interface "lan1"
        set vlanid **
    next
end

config system settings
    set allow-subnet-overlap enable
end

config router static
    edit 1
        set dst 0.0.0.0 0.0.0.0
        set status disable
        set device "wan1"
    next
end

config router ospf
    set default-information-originate enable
    set router-id **.**.**.**
    config area
        edit 0.0.0.0
        next
    end
    config network
        edit 1
            set prefix **.**.**.0 255.255.255.0
        next
    end
    config redistribute "connected"
        set status enable
    end
    config redistribute "static"
        set status enable
    end
end

主要な部分を抜き出すとこんな感じ。

注意するべきところをいくつか説明しておきましょう。

config system settings
    set allow-subnet-overlap enable
end

allow-subnet-overlap という設定、同一サブネットに属する IP アドレスを複数のインターフェースに付与されることを許可するという設定です。Fortigate の Unnumberd PPP の設定でぐぐると、これを設定しろって出てくるんだけど、config system global モードで設定する。となってるんですが、Firmware Ver.5.4 付近からモードが変わったようです。

次にインターフェース関係

config system interface
    edit "wan1"
        set vdom "root"
        set mode pppoe
        set ipunnumbered **.**.**.**
        set username "***"
        set pppoe-unnumbered-negotiate disable
        set password ENC ***
    next
    edit "vlan-gbl"
        set vdom "root"
        set ip **.**.**.** 255.255.255.**
        set interface "lan1"
        set vlanid **
    next
end

ここでインターフェース wan1 は PPPoE をしゃべらせるインターフェース、vlan-gbl は払い出される /29 とかのサブネットを持つインターフェースです。ポイントは、wan1 の set unnumberd *** コマンドと、vlan-gbl の set ip コマンド。この二つには同じ IP アドレスを設定します。pppoe-unnumbered-negotiate は PPP で振り出されたアドレスをwan1 インターフェースにそのまま付与しちゃダメって意味らしいです。

さて、次へ行きましょう。

config router static
    edit 1
        set dst 0.0.0.0 0.0.0.0
        set status disable
        set device "wan1"
    next
end

スタティックルートの設定です。

が、よーく見てみると、この設定、status disable になってます。つまり、この設定は不要です。何が言いたいかちうと、Default route を PPP に向けてあげる必要はないです。ということ。

FortiOS は PPP を設定すると、自動的に PPP に Default route を向けるようです。

最後に OSPF の設定について

config router ospf
    set default-information-originate enable
    set router-id **.**.**.**
    config area
        edit 0.0.0.0
        next
    end
    config network
        edit 1
            set prefix **.**.**.0 255.255.255.0
        next
    end
    config redistribute "connected"
        set status enable
    end
    config redistribute "static"
        set status enable
    end
end

探してみると、Fortigate でOSPFを設定する話、あんまり見かけないんですよね。

ポイントとなるのは default-information-originate の設定。これは Default route を OSPF に乗せるという設定です。これを設定しておかないと、いくら Static route で Default route を設定しても、OSPF に流してくれません。

あと、router-id。必須ではないみたいなんですが、これを正しく設定しないと、Neigber が確立しないことがありました。

ユビキタスエロゲ

| コメント(0) | トラックバック(0)

ユビキタスってことば、すーっかり聞かなくなりましたが、「いつでもどこでも」みたいな意味です。ある人は、八百万(やおよろず)コンピューティングって言ってて、凄い納得した記憶が

で、ユビキタスエロゲって?ってことなわけですが、いつでもどこでもお気楽にエロゲをプレイするには?というお話

ノートパソコンでエロゲするんでしょ?って思うでしょ?まぁ、そうなんですが、それだけじゃないんです。何が問題か?普段はデスクトップなり大型ノートなりの据え置き機でエロゲをプレイしているという前提で考えてみます。

まず、何が問題なのか、課題を明確にしましょう。

  • Windowsアプリケーションなので、同じエロゲを別マシンで動かすには逐次インストールしないといけない
  • インストール時のコピーサイズが大きいのでインストールに時間がかかる
  • セーブデータの保存フォルダを変更できないので、セーブデータの管理ができない

エロゲとエロゲ以外のWindowsアプリケーションの動作環境の違いを考えてみましょう。

VGD02.pngVGD03.pngOffice のような Windows アプリケーションの場合、Officeだ、Photoshopだのアプリケーションを一回インストールすれば、あとはユーザが作ったデータファイルのが増えるだけで、アプリケーションを次々インストールすることは少ないでしょう。ところがエロゲの場合、その作品をコンプリートしたら新たなアプリケーションとして次の作品をインストールする必要があります。

しかも、それぞれの作品がOP/EDの動画やキャラクターボイスのような大きいデータを抱えています。

さらに、エロゲには音楽とキャラクターボイスが重要、すなわちオーディオ機能が重要な役割を果たします。Officeなどのビジネスアプリケーションではオーディオのことはほとんど何も考えてませんから、あの手のソフトと同じような考え方はできません。

あと、なにげに重要なのが光学ドライブ。使うのはインストール時だけですが、プロテクトがあるので、これもビジネスアプリケーションとは考え方が変わります。

この話をすると、「え?VDIにすりゃいいんじゃないの??」と言われるんですが、VDIはオーディオも動画もない、ファイルサーバさえあればマシン一台のストレージなんて128GBもあれば十分でしょ?っていうビジネスアプリケーションのことしか考えてない代物にしか通用しないことをご理解いただけるかと。

というわけで、どんなソリューションがあるかなぁと試行錯誤した結果をまとめておきます。

セーブデータのみをクラウドストレージで同期する

パソコンごとに逐次インストールしないといけない問題はあきらめます。デスクトップ機、ノート機各々にエロゲをインストールして、セーブデータだけを共通化することで、どのマシンを使っても、シナリオの続きをできるようにすることを考える方法です。

VGD04.png準備する必要があるのは

  • クラウドストレージの仕組み (ownCloudとかDropBoxとか)
  • オンプレのクラウドストレージ(ownCloud)を使う場合はそのサーバ
  • 各作品のセーブデータ保存場所の情報

セーブデータの保存場所にはパターンがあって、作品ごとに異なります。候補となるフォルダをリストアップするので、作品ごとに探してください。

  1. C:\Program Files\作品名\Data
  2. C:\Users\ユーザ名\AppData\Local\VirtualStore\Program Files\作品名
  3. C:\作品名\Data
  4. C:\User\ユーザ名\AppData\Roamin\作品名
  5. C:\User\ユーザ名\Documents\作品名
  6. C:\User\ユーザ名\Saved Games

WinXP 時代以前の作品はほとんどが 1. です。ところが、WinVistaから C:\Program Files 以下への書き込みがシステムで制限されるようになりました。WinVista以降のマシンに、WinXP世代の作品をインストールすると、2. の場所にセーブデータが保存されます。

仮想化プラットホームにエロゲマシンを構築する

いわゆるVDI環境です

VGD05.png別に仮想化が必須なわけではありません。デスクトップのエロゲマシンを常時起動できるのであれば、それを使っても同様の環境が実現できます。

準備する必要があるのは

  • 常時起動しているエロゲ環境 (仮想化でも物理でもよい)
  • 画面転送プロトコルを実現できる仕組み

注意しないといけないのが、画面転送プロトコル。「え?リモートデスクトップでしょ?」と思うあなた。それで十分かどうか、確認してみてください。

リモートデスクトップはMS社製です。ヤツらはビジネスのことしか考えてません。ビジネスにはオーディオや動画はあまり重要じゃないのです。なので、リモートデスクトップではオーディオや動画再生はうまくいかない場合があります。コマ落ちしたり、音飛びしたり。

サーバやクライアント、ネットワークに十分な余裕があれば、リモートデスクトップでも大丈夫です。あと、リモートデスクトップはサーバ側がPro Edition以上でないと使えません。Win10時代になって、Pro Edtion 搭載マシンを買いにくくなってるので、これも難点です。

というわけで、画面転送プロトコルに別のものも検討しておきます。「動画をリモートで再生すること」を目的と唄ったフリーソフトです。

昔からある、VNCは音声転送がそもそもできませんので、この要件には使えません。

ホスト型仮想環境にエロゲマシンを構築する

いまのところ、本命はこれ

VGD06.png実際の作品は各マシンのリソースを使って動くのですが、仮想マシンのイメージディスクをファイルサーバに置くことでインストールを1回で済ませることができます。モバイルマシンでプレイしたい場合は、イメージファイルをコピーすれば持ち出せます。ファイルは大きいですが、インストール処理は要らないので、マシン間移動が比較的楽なのがメリット。

ただし、この方法、大きな弱点があります。プロテクトに狙い撃ちされる場合があります。SecuROM は VMware を検知してインストーラに蹴られます。ういんどみるの作品はこの問題でインストールできません。

あと、ネットワークの影響も要確認です。VDI方式の場合は遅延が効きますが、こっちの方法だと帯域が効きます。

準備する必要があるのは

  • 仮想化ソフトウェア (VMware Player や VirtualBOX)
  • ファイルサーバやNAS(イメージをローカルにコピーするのであれば不要)

例によって、Hyper-Vは?というと、例のごとくヤツはMS品なのでビジネスのことしか考えてません。オーディオ機能が提供されていないので話になりません。

まとめ

これがベストだ!というのがないのが実情ですね

Windowsの仕様というか、歴代Windowsの仕様変更と、プロテクト対応がメンドクサイです。

ownCloud、便利です

Dropbox みたいな、クラウドストレージなんですが、オンプレで動かせる。つまり、サービス提供側が、やーめた(てへっ)とか言う心配がない。ストレージ容量も自分次第。WindowsもAndroidもいける。

完璧!!・・・と思ってたんですが。

Windows版のクライアントソフト、けっこー頻繁にアップデートが出ます。んで、クライアントが自身で勝手にアップデートします。それ自体はいいんですが・・・・・そのアップデートを止める設定がない。クライアントバージョンを塩漬けして使いたい。って思うと、勝手に走り出すインストーラを、UACに引っ掛けて、そこで止めるしかないのですよ。

んでまって、このクライアント、Windows版のVer.2.4.2あたりから旧バージョンのサーバへの接続を強制的に切るということを始めやがりました。Android版も、2018年12月初頭付近に出たバージョンから旧バージョンのサーバ、Ver.8系、Ver.9系への接続を切るということを始めやがりました。

いや、正しいとは思うですよ?その行為。旧Verのサーバのままにしておくのは悪いことですよ。だけどね、サーバ、クライアント含めて塩漬けする。って方針を潰すってどーなんかね?

Win10 でユーザの意向を無視して強制アップデートするっていうのを許す風潮、すげぇ嫌


とまぁ、ボヤいててもしょーがないので、ownCloudサーバのバージョンアップをして見ます。

occ コマンドでバージョンアップするんだよーっていうのは、よく出てくる話なんですが、いくつか補完情報をまとめておきます。

ポイントは2つ

  1. pecl-intl というツールが必要
  2. アップグレードパスに注意

まず pecl-intl ですが、初期インストール時に www/owncloud をインストールしただけでは依存性インストールされません。

なので、devel/pecl-intl がインストールされてるかを確認して入ってなければインストールしましょう。

次にアップグレードパス。

Ver.9.1 からは直接 Ver.10.0 にアップグレードできます。

Ver.8.2 からは Ver.9.0 を経由して Ver.10.0 にアップグレードします。

注意しないといけないのが、Ver.8.2 からは Ver.9.1 へアップグレードできないので、Ver.9.0 を経由するということ。

旧バージョンのインストールファイルは、公式サイトから取ってきましょう。

実際のコマンドラインはこんな感じ

# cd /usr/local/www/owncloud
# php ./occ maintenance:mode --on
# /usr/local/etc/rc.d/apache24 stop
# cd /usr/local/www
# mv owncloud owncloud.old
# bunzip2 -c owncloud-10.0.10.tar.bz2 | tar xvf -
# chown -R www:www owncloud
# mv owncloud.old/data owncloud/
# cp owncloud.old/config/config.php ownclud/config
# chown www owncloud/config/config.php
# cd /usr/local/www/owncloud
# php ./occ upgrade
# php ./occ maintenance:mode --off
# /usr/local/etc/rc.d/apache24 start

あとはクライアントからの接続テストをしておしまい

あ、書くの忘れてた。FreeBSD でのお話ですよん

そーいや、サーバもVer.10から、FreeBSDは動作保障しないとか言い出してたような。だったら、旧バージョンを使えなくする処置をするなよな・・・・・

エアコン設置完了

R0012091.JPGよーやくエアコン設置が終わりました。当初はエアコン設置も自前で行けるんでね?って思ってたんですが、真空ポンプが必要ってことで、こりゃームリ!ってことで、父親の友人の電気屋さんに工事依頼したんですが・・・・・この作業待ちで3週間くらい止まってました。

ラック設置

さーて、いよいよ本格的に機材の搬入をしましょう。まずはラック。

R0012092.JPGすでにUPSとか、サーバ機とか置いちゃってますが、ラックを起きます。

自宅ラックの人たちの間でも、「もうメタルラックは捨てて、19インチラックを入れるべき」っていう意見があるのですが、うちはメタルラックです。理由はラックマウント機器が少ないから。ストレージがQNAPのタワーというかボックス型NAS、サーバもほとんどがタワー機なので、19インチラックを入れたとしても、メタルラックなりが必要なんですね。

じゃあってことで、全部メタルラックです。

ちなみに、メタルラックシリーズといえば、奥行き 46cm しかなかったんですが、新たに奥行き 61cm シリーズが追加されました。19インチラックに収めるような機材の場合、奥行き 46cm だとはみ出しが多くて安定性に問題ありなんですが、奥行き 61cm の棚にすると安定して置けます。

というわけで、サーバ機器用として 610 × 1200 のラックを一台、ストレージ機器用として 460 × 1200 のラックを1台、L字型に置くことにしました。

全景を見渡すとこんな感じ

R0012096.JPGもーちょっと広い建物にしたかったなぁーと思わないでもないですが、まぁそう言い出すと際限なく広くなりそうなので、これくらいで。

電源配線

電源関係を配置していきます。

R0012101.JPG特に電源が2系統以上あったりする場合は、ラベリングが非常に重要。これは絶対にやらないとダメです。

「どうせ一人で管理するんだし、線なんてたどればいいんだよ」って思ってた過去の私、そこに正座。「え?この線ってどっち?」とか言って引っ張ったらコンセント抜けてぎゃー!!って叫ぶことになります。

ケーブルは両端にラベリングしましょう。

R0012100.JPGケーブルにラベリングするときは、ラベル付きのタイラップが便利です。電気工事系の資材を扱ってる店の、タイラップコーナーにほぼあるので、探してみてください。

R0012098.JPGUPSも設置します。重いのと、ラック設計の慣例に習って、一番下の棚に。

R0012102.JPGメタルラックにそのまま置くと、ゴム足が棚板の隙間から下に落ちるので、硬質シートを敷いておくと良いです。

イバナ物置DCにすると、天井はそんなに高くありません。190cm くらいの天井高です。そして、断熱材を固定するために、金属の梁が入ってます。

R0012095.JPGつまり、こんな取り付け方ができます。案外これが便利。ちなみに、使ってるACタップはたのめーるオリジナルブランドのタップ。3Pコンセントでロック機能付きのACタップってけっこー高いんですが、たのめーるのこれ、安いんですよね。

機材搬入

ネットワーク機材を搬入して配線します。

R0012114.JPGR0012115.JPGポート数、多すぎだろ?って気もしますが、気にしなーい

R0012119.JPGストレージ装置。QNAPを全部で5台入れる予定ですが、3台は旧サーバ室で稼働中なので、まずは2台を搬入。稼動状態に入れて、Storage vMotion を使いながら、残り3台も順次搬入の予定です。

R0012120.JPGサーバ機は運用終了しているマシンも含めて6台を搬入予定ですが、こっちもまだ半分しか搬入できてません。vMotion で順次仮想マシンを空にして移設予定です。

Storage vMotionをちまちまやる必要があるので、全機器搬入には1ヶ月くらいはかかるかなぁと。

R0012122.JPG運用を開始して最初の夜。データセンタ内の証明を消すと、をを!!なんかデータセンターっぽい!

商用データセンターとかで仕事終わって退館するとき、証明を消すとマシンルーム全体がLEDの光だらけになるんですね。DC作業が無事に終わったあとにこれをみると、おぉ、綺麗だ!って気になるんですよ。まぁ、作業がうまく終わらず、宿題持ち帰りになった場合は、そんな余裕もまったくないんですけどね。

インシデント

機材搬入中に、部外者の侵入をゆるしてしまいました。インシデントです。

R0012112.JPG機材搬入中はドアを開けっ放しにするので、DC運用者の皆さん、注意しましょう。

Zabbix4が出ました。ちうても、もう1,2ヶ月前ですが・・・・・

いい加減、Ver.2.0 の Zabbix もどないかせんとなぁ、と思ってたのですが、思い切ってあげてみることに。とはいえ、切り替えなんてムリだしょ?ってことで、現行のVer.2.0と、Ver.4.0を並行運用します。

まぁ、仮想環境なんで、Zabbix サーバマシンをもう一個作るのはそんなに難しい話じゃない。Zabbix Agent 側も上位互換があるので、当面は今はいってるAgentのまま行けるっしょ

ちなみに、Agent 側は、zabbix_agentd.conf に Server=server1,server2 とコンマ接続でサーバを列挙すれば、両方から監視できます。

Zabbix Server Ver.4 から Agent Ver1 から Ver.4 まで監視できます。逆にServer Ver.2.0 では、Agent Ver.4 は監視できませんでした。


さてさて、Zabbix 4 なんですが、立ち上げてみたら一個問題が。

SNMP でスイッチを監視しようとしたら、ポートごとのインターフェーストラフィックが取得できない。

zabbix-1.png「そんなOIDねーよ」って言われちゃいます。

なんで・・・?と調べてみたところ、取得してるMIB値が net.if.in[ifHCInOctets.1] になってるんですね。

MIB 値 ifHCInOctets ちうのは、インターフェースごとの In 方向オクテット数なんですが、64-bit カウンタです。

SNMPって、もともと数値は 32-bit までだったのが、数年前(もう10年くらい経つ?)から64-bit カウンタが使えるように拡張されました。

なもんで、ifHCInOctets は必ず対応してるとは限りません。一方、32-bit カウンタはifInOctets という MIB で、こっちはまぁほぼ間違いなく対応してます。

ちうわけで、Zabbix 4 に 32-bit インターフェースカウンタを読ませましょう。という話です。

要約したら、「Zabbix のテンプレート弄って追加しろ」ってだけなんですが、

[テンプレート]-[Template Module Interfaces SNMPv1]-[ディスカバリールール]-[Network Interfaces Discovery]-[アイテムのプロトタイプ] を開きます。

[Interface {#IFNAME}({#IFALIAS}): Bits received] をクローンすると早いでしょう。32-bitカウンターを追加します。

zabbix-2.png変更するのは、名前(64-bitカウンタとかぶるとダメなので)、キー、SNMP OID。

名前キーOID
Interface {#IFNAME}({#IFALIAS}): Bits received net.if.in[ifHCInOctets.{#SNMPINDEX}] 1.3.6.1.2.1.31.1.1.1.6.{#SNMPINDEX}
Interface {#IFNAME}({#IFALIAS}): Bits received(32-bit) net.if.in[ifInOctets.{#SNMPINDEX}] 1.3.6.1.2.1.2.2.1.10.{#SNMPINDEX}
Interface {#IFNAME}({#IFALIAS}): Bits sent net.if.out[ifHCOutOctets.{#SNMPINDEX}] 1.3.6.1.2.1.31.1.1.1.10.{#SNMPINDEX}
Interface {#IFNAME}({#IFALIAS}): Bits sent(32bit) net.if.out[ifOutOctets.{#SNMPINDEX}] 1.3.6.1.2.1.2.2.1.16.{#SNMPINDEX}

 既存の 64-bit カウンターと並べて、こんな感じの監視キーを作ってあげます。

zabbix-3.pngこれで無事監視できるようになりました。

内装工事

さて、建物できたので、よーやく内装関連です。電源関係とネットワーク関係。データセンターなんですから、電源とネットワークが来ないことには話になりませんわな。

まぁ、Tier1 以上の本物だと、その外にも消火設備だとか、入退室管理システムだとか、あれこれあるですが、それはやりません。

というわけで、まずは地面に埋めたボイド管にケーブルを通します。いきなりパイプにケーブルを押し込んでも、そんなもん入るわけないので、まずはケーブルを引っ張る針金をとおします。

R0012013.JPG白飛びしてて見にくいですけど、右手に伸びてる青っぽいのが通した針金です。

んで、これを引っ張ってまずは電源ケーブル。

R0012014.JPGシステム用の正、副に加えて、エアコンとか用の予備で3系統引き込んでます。さらにケーブルを通しましょう。

R0012015.JPG手前の灰色が先に通した電源。オレンジ色のが光ファイバーケーブル。黒いのがテレビアンテナ用の同軸線です。なお、この光ファイバーケーブル、ヤフオクで買った代物なんですが、500フィートのリールが3個で1万円という代物。この工事が終わってもまだ1本目のリールを使い切ってません。残ってるケーブル、何に使おう・・・・?

ケーブルをデータセンタ室内に引き込むとこうなります。

R0012018.JPGんでまって・・・・・どーやらこのあたりから、父親がすごいやる気を出しまして。電源回りの内装がえらい本格的に。当初の計画では、ケーブルの先にOAタップ付けときゃいーだろ!って思ってたら、こんなんできてきました。

R0012044.JPG鼠色の箱はブレーカ箱です。あと、室内コンセントはこんな感じ。

R0012055.JPG冬はエアコンなしで行けるようにということで、家庭用の換気扇も設置。

R0012046.JPGそれから、室内照明

R0012047.JPGこの照明装置、オーム電機のLT-NLDM14D-HLっていう製品なんですが、いかにも!!っていう感じのLED照明。最近のデータセンターって、照明がLEDなのがほとんどなんですが、この照明で照らすと、いかにもデータセンターって雰囲気になります。(個人の感想であって効果をうんうんかんぬん)

光ファイバーの終端は例によってSCコネクタをつけて、木の板に固定します。実際の接続は光パッチケーブルで。

R0012049.JPGなお、エアコンはさすがに自前で工事は難しいので、電気屋さんにお願いする予定です。

エアコン取付が終わったら、いよいよマシンを入れていきましょうかね。

お断り

このネタは萌えるか萌えないかというネタです。なので、次のような人々はご遠慮ください。

  • 「好き/嫌い」と「良い/悪い」「正しい/間違ってる」を区別できない人
  • 萌えが気に食わないからと存在を消滅させたいような連中
  • 人工知能が人間の領域を犯すとか言ってる人たち

人工知能を萌えさせてみよう

まぁ、人工知能ちうか、Deep Learningしてみようという話です。

ことの発端は Twitter。Twitter眺めてると、イラストを投稿してくれる絵師さんがけっこーいらっしゃいます。で、いいなぁこれ!ってなったら、保存しちゃうわけですが、TL見てないときにイラストが流れてたりすると、見逃してしまうわけです。

んじゃ、API 使って片っ端からダウンロードしたらどだろ?と

ダウンロードしてみました。

DownloadPlain.pngん・・・・・・期待してたのと、ちょーっと違うかなぁ。期待してたイラストダウンロードされてはいるんですが、なんかそうじゃないのもけっこー混ざってる。実写写真とか、DVDとかの宣伝画像とかとかとか・・・・

言い換えると、萌える画像と萌えない画像が混ざってる。

しかも、自動でダウンロード走らせてしまったもんだから、1000万個ちかくのファイルができてしまった。

こんなの、とーてー目視で振り分けなんぞやってられん!ということで、自動ふるい分けできんか??と考えたわけです。

これって、いってみりゃ画像認識なわけです。画像認識と言ったら Deep Learning!

さぁ、Deep Learning で萌える画像と萌えない画像を識別させてみよう!

よくあるDeep Learningは、「これは犬の写真です」「これは自動車の画像です」みたいな、物の形を識別するものがほとんどです。同じ仕組みで、「萌えるか萌えないか」すなわち、「好きか嫌いか」を識別できるのか??というのが新しい点かなと。

教師データの準備

まずは教師データの準備をば。

こればっかりは手動で振り分けるしかありません。手作業でこれはイイ!という画像を集めます。

萌える画像をごそっと。おおよそ3000枚

GoodTeacher.png次に萌えない画像もやっぱり3000枚ほど。あくまでも萌えない画像、すなわち、私が好きじゃない画像です。良いとか悪いとか、うまいとか下手とかじゃありません。念のため

BadTeacher.pngなお、実際には「うーん、これはどっちだ。判断できん」という保留も2000枚くらい出てきてます。これはDeep Learningの教師データには使いません。

しっかしまぁ、どっちもエロ画像ばっかりやな(を

スクリプトをごりごり

学習させるためのデータが準備できたので、次はDeep Learningの実装。

import os
import numpy
import chainer
import chainer.functions as func
import chainer.optimizers
import random
import cv
import cv2
import io
import sys
import psycopg2
import pickle
import datetime
import locale

from PIL import Image

locale.setlocale(locale.LC_ALL , 'ja_JP.eucJP')

"""
model = pickle.load(open("model" , 'rb'))
"""
model = chainer.Chain (
    conv1 = func.Convolution2D( 3, 32, 3, pad=1),
    bn1   = func.BatchNormalization(32),
    conv2 = func.Convolution2D(32, 32, 3, pad=1),
    bn2   = func.BatchNormalization(32),
    conv3 = func.Convolution2D(32, 32, 3, pad=1),
    conv4 = func.Convolution2D(32, 32, 3, pad=1),
    conv5 = func.Convolution2D(32, 32, 3, pad=1),
    conv6 = func.Convolution2D(32, 32, 3, pad=1),
    l1    = func.Linear(2048 , 512),
    l2    = func.Linear(512 , 2))

def forward(x):
    x = chainer.Variable(numpy.array(x, dtype=numpy.float32), volatile=False)
    h = func.max_pooling_2d(func.relu(model.bn1(model.conv1(x))), 2)
    h = func.max_pooling_2d(func.relu(model.bn2(model.conv2(h))), 2)
    h = func.max_pooling_2d(func.relu(model.conv3(h)), 2)
    h = func.max_pooling_2d(func.relu(model.conv4(h)), 2)
    h = func.dropout(func.relu(model.l1(h)))
    h = model.l2(h)
    return h

optimizer = chainer.optimizers.Adam()
optimizer.setup(model)

def lean(pic , priority):
    t = chainer.Variable(priority.astype(numpy.int32))
    h = forward(pic)
    optimizer.zero_grads()
    d = func.softmax_cross_entropy(h, t)
    d.backward()
    optimizer.update()

    if(h.data.argmax() == priority):
        return True
    else:
        return False

def load_norm_img(imgpath):
    img  = Image.open(imgpath)
    img  = img.resize((128 , 128))
    img  = img.convert('RGB')
    img  = numpy.asarray(img)
    img  = img.transpose(2,0,1)
    img  = numpy.expand_dims(img, axis=0)
    
    return img

def dir_lean(good_dir , bad_dir):
    good_files = os.listdir(good_dir)
    random.shuffle(good_files)
    bad_files  = os.listdir(bad_dir)
    random.shuffle(bad_files)
    num = min([len(good_files) , len(bad_files)])

    hit = 0
    count = 0
    for i in range(0 , num):
	count += 2
	file = good_dir + "/" + good_files[i]
	img = load_norm_img(file)
        pri = numpy.array([0])
	if(lean(img , pri)):
	    hit += 1
	file = bad_dir + "/" + bad_files[i]
	img = load_norm_img(file)
        pri = numpy.array([1])
	if(lean(img , pri)):
	    hit += 1
    per = (hit * 100) / count
    print(str(hit) + " / " + str(count)) + " ( " + str(per) + "% )"

for i in range(0 , 20):
    print("Epoch " + str(i))
    dir_lean("good" , "bad")
    print(">>Update saved module<<")
    pickle.dump(model , open("model" , 'wb') , -1)

こんなかんじ!

いやね、このBlogネタ書こうと思ったのは、このコードを書きたかったんですよ。このコード書くときに、Chainerってどーやって書くの?だれかサンプル公開してないの??って思って調べたんですが、全然出てこなかったんですよ。なもんで、じゃあ動くのできたらまるごと晒してみようかなと。

ただーし!このコード、拾い物の情報とか試行錯誤とかして書いたやつなので、本当に正しいの?と言われたら、さぁ?としか・・・・間違ってたら、だれかおせーて。

主要な部分を解説しましょう。

def load_norm_img(imgpath):
    img  = Image.open(imgpath)
    img  = img.resize((128 , 128))
    img  = img.convert('RGB')
    img  = numpy.asarray(img)
    img  = img.transpose(2,0,1)
    img  = numpy.expand_dims(img, axis=0)

    return img

画像をファイルから読み込むサブルーチン。ファイルから読み込んで、128x128の解像度に縮小します。読み込んだ画像は当然二次元のデータですが、ニューラルネットワークに突っ込むには一次元配列にしないといけない。なので、そのための一次元化処理もこの中でやってます。

"""
model = pickle.load(open("model" , 'rb'))
"""
model = chainer.Chain (
    conv1 = func.Convolution2D( 3, 32, 3, pad=1),
    bn1   = func.BatchNormalization(32),
    conv2 = func.Convolution2D(32, 32, 3, pad=1),
    bn2   = func.BatchNormalization(32),
    conv3 = func.Convolution2D(32, 32, 3, pad=1),
    conv4 = func.Convolution2D(32, 32, 3, pad=1),
    conv5 = func.Convolution2D(32, 32, 3, pad=1),
    conv6 = func.Convolution2D(32, 32, 3, pad=1),
    l1    = func.Linear(2048 , 512),
    l2    = func.Linear(512 , 2))

次にモデル定義。これがニューラルネットワークの定義そのものです。畳み込み処理を2段通したあと、2048ノード、512ノード、2ノードの3層ネットワークです。
コメントアウトしてあるpickle.loadは、学習させたネットワークを保存しておいたものを読みだすときに使う処理。メインループでpickle.dump使ってmodel変数の中身、つまりネットワークをファイルに書き出してますが、これを読み込む場合はコメントアウトしたload処理を有効化して、変わりにmodel変数の定義をコメントアウトします。

def forward(x):
    x = chainer.Variable(numpy.array(x, dtype=numpy.float32), volatile=False)
    h = func.max_pooling_2d(func.relu(model.bn1(model.conv1(x))), 2)
    h = func.max_pooling_2d(func.relu(model.bn2(model.conv2(h))), 2)
    h = func.max_pooling_2d(func.relu(model.conv3(h)), 2)
    h = func.max_pooling_2d(func.relu(model.conv4(h)), 2)
    h = func.dropout(func.relu(model.l1(h)))
    h = model.l2(h)
    return h

つぎはネットワークの伝搬処理の実装部。ニューラルネットワークの第一層から第二層への伝搬はRelu関数とDropout関数を通して、第二層から第三層へは関数なし、つまりは線形関数で伝搬します。

def lean(pic , priority):
    t = chainer.Variable(priority.astype(numpy.int32))
    h = forward(pic)
    optimizer.zero_grads()
    d = func.softmax_cross_entropy(h, t)
    d.backward()
    optimizer.update()

    if(h.data.argmax() == priority):
        return True
    else:
        return False

最後に学習処理の本体。forwardで順方向伝搬をしたあと、伝搬結果を評価して、逆伝搬して、モデルをアップデートする。という処理をそのまんま流してます。

この関数と、forwad() 関数の中でVariable()関数を読んでますが、どうやらChainerで使う変数次元に合わせる関数のようで、お約束的に使うっぽいです。

さて結果は

教師データもそろった。処理系もできた。さぁ学習しましょう。

スクリプト内でパーセント値をprintしてる部分がありますが、画像を準に学習する際に、順伝搬させてその結果が期待している判定に一致した率を表示してます。

エポックが進むに従い、この割合が上がっていくことを期待して眺めるわけですが、なんと20から30エポックくらいで90%程度に達して、それ以上は上がらなくなりました。9割正しく判定できたら、まぁ十分じゃね??

というわけで、自動判定をしてみます!

まずは萌えると判定された画像

GoodResult.png次に、萌えないと判定された画像

BadResult.png赤四角で囲ったのが判定ミスしてるものです。

完璧とは言えないけど、まずまず十分に使い物になるレベルじゃね?

どっちにしたところで、エロ画像ばっかりやんけ!っていうのはおいておいて

建築!

さーて、ようやく建築です。といっても、基本的にイナバのマニュアルどおりなんですが。マニュアルどおりに建てるだけなら、たぶん1日でできるんじゃないかしら?

まずは土台を組んで、基礎に乗せます。

R0011987.JPG土台の四隅は地中に埋め込んだ基礎を使って固定します。

R0011988.JPG基礎を固定したら、柱を立てます。

R0011989.JPG次は梁を乗せます。元の部材が良くできてて、柱に引っ掛けてからねじを締めるだけ。これは良く考えられてますねぇ

R0011993.JPG以上で骨格ができるので、次は板をつけて回ります。屋根板と壁板の取り付け。

R0012004.JPG

壁板と屋根板は板状の固定パーツで柱や隣の板に固定してからねじでとめます。と言っても、これは説明しにくいので、実際に建てる人はマニュアルをよーっく見てくださいませ。マニュアルの絵と実物を見比べるとまぁなんとかなるでしょう

R0012000.JPGマニュアルどおりに組んでいくと、こんな感じで色違いの金属部材を取り付けることになります。これらは、室内に断熱板を固定するための固定具です

R0012005.JPG取り付ける断熱材はこんな感じ。発砲スチロールの板で、この写真は裏面。ちょーっと薄い気もするんですが、その真価は来年の夏にわかるでしょう。

R0012011.JPG断熱材はそのまま内装材を兼ねてるので、断熱材を取り付けると、内装が完成します。

R0012016.JPGドアを取り付けて、建物の囲みが完成します。

R0012017.JPG

物置の部材として同梱されてるものはこれですべてで、建物としての役割は十分です。が、壁と天井が全面断熱材に覆われてるのに、床だけが金属の板だったりするんですね。

R0012032.JPG床下からの湿気とか、断熱とか、入室時の歩き心地とかを改良したいので、養生シートと合板を敷きます。

R0012036.JPG以上で建物は完成。

メーカはおそらく基礎工事含めて2,3日でここまでくることを想定してるのかなぁという感じですが、基礎工事だなんだを含めたら、そろそろ一ヶ月はかかってるような・・・・

配線の準備

データセンターなので、当然のことながらネットワークと電源は必須。

当然ながら、有線配線します。自宅の裏庭に建てるので配線も自分でできます。まぁ、電気工事のうち、ブレーカーさわったりは電気工事士の資格が必要なんですが、これは父親が資格もってるのでお任せの方針で。

実際に配線するのはもっと後なんですが、線を通す準備だけしておきます。

使うのはこれ

R0011965.JPGPF管という配線を通す専用の管です。

まずはPF管を埋めるために溝を掘ります。

R0011967.JPGR0011969.JPGR0011971.JPGそして、管を入れる

R0011975.JPG最後に埋める!

R0011982.JPG管の端は接続箱につなぐわけですが、この作業はまだ保留。

R0011976.JPG管を通したりするために、木の根を切ったりしてますが、まぁ大丈夫でしょう。

15mくらい溝掘って埋めるのにほぼ一日かかり。全身筋肉痛になりますた。

なお、この管3本に電源3系統、光ファイバー4対、テレビアンテナ用同軸ケーブル1本を入れる予定ですが、それはまた今度