suzuzusu日記

(´・ω・`)

ffmpeg filterの作り方

そろそろブログまとめようと思ったので移転記事です.

移転元 https://wiki.mma.club.uec.ac.jp/su_zu/ffmpeg%20filter%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9

MMA Advent Calendar 2016/12/21

これはMMA Advent Calendar 2016の21日目の記事です

ffmpeg filterとは

https://trac.ffmpeg.org/wiki/FancyFilteringExamples

標準でffmpegにはマンデルブロ集合とかライフゲームなどの面白いfilter機能がついています。今回はそのfilterの作り方を説明します。Libavfilterから直接作ることもできるのですが今回はFrei0rで作る方法を記述します。実際の動画編集はノンリニア編集するほうが便利ですが生配信などにはもしかして自作フィルターが使えるかもしれません(?)

Frei0r

Frei0rというのはクロスプラットフォームのvideo effect pluginです。最近の新しいffmpegはfrei0rに対応しています。ffmpeg -versionして--enable-frei0rと表示されていれば対応しています。

#include "frei0r.hpp"
#include "frei0r_math.h"
#include <stdlib.h>

// frei0r::filterを継承して作っていきます
class Mat33 : public frei0r::filter
{
public:
  Mat33(unsigned int width, unsigned int height)
  {
    // register_paramで引数を登録することができます
    register_param(m11, "m11", "matrix element m11");
    register_param(m12, "m12", "matrix element m12");
    register_param(m13, "m13", "matrix element m13");
    register_param(m21, "m21", "matrix element m21");
    register_param(m22, "m22", "matrix element m22");
    register_param(m23, "m23", "matrix element m23");
    register_param(m31, "m31", "matrix element m31");
    register_param(m32, "m32", "matrix element m32");
    register_param(m33, "m33", "matrix element m33");
  }

  // updateで一フレームごとの処理を書いていきます
  // inに編集前ピクセルデータがあり、outに編集後のピクセルデータを入れます
  virtual void update(double time,
                      uint32_t* out,
                      const uint32_t* in)
  {
    std::copy(in, in + width*height, out);
    for (unsigned int y=1; y<height-1; y++){
      for (unsigned int x=1; x<width-1; x++){
        unsigned char *p1 = (unsigned char *)&in[(y-1)*width+(x-1)];
        unsigned char *p2 = (unsigned char *)&in[(y-1)*width+x];
        unsigned char *p3 = (unsigned char *)&in[(y-1)*width+(x+1)];
        unsigned char *p4 = (unsigned char *)&in[y*width+(x-1)];
        unsigned char *p5 = (unsigned char *)&in[y*width+x];
        unsigned char *p6 = (unsigned char *)&in[y*width+(x+1)];
        unsigned char *p7 = (unsigned char *)&in[(y+1)*width+(x-1)];
        unsigned char *p8 = (unsigned char *)&in[(y+1)*width+x];
        unsigned char *p9 = (unsigned char *)&in[(y+1)*width+(x+1)];

        unsigned char *o = (unsigned char *)&out[y*width+x];
        for (int i=0; i<3; ++i){
          o[i] = CLAMP0255(abs(p1[i]*m11 + p2[i]*m12 + p3[i]*m13 + p4[i]*m21 + p5[i]*m22 + p6[i]*m23 + p7[i]*m31 + p8[i]*m32 + p9[i]*m33));
        }
        o[3] = ((unsigned char*)&in[y*width+x])[3];
      }
    }
  }
private:
  f0r_param_double m11;
  f0r_param_double m12;
  f0r_param_double m13;
  f0r_param_double m21;
  f0r_param_double m22;
  f0r_param_double m23;
  f0r_param_double m31;
  f0r_param_double m32;
  f0r_param_double m33;
};

// filterの登録処理です
frei0r::construct<Mat33> plugin("Mat33",
                                "3*3 Matrix filter",
                                "su_zu",
                                0,1,
                                F0R_COLOR_MODEL_RGBA8888);

上の例は3×3行列のフィルター処理を行えるフィルターを書いてみました。なんかフィルターフィルター言っててわかりづらい。。。

How to Use

# buildしたfilter DLLのmat33.dllをC:\Program Files (x86)\frei0r\lib\frei0r-1に置いたとしましょう

#FREI0R_PATH環境変数を設定
$ export FREI0R_PATH="C:\Program Files (x86)\frei0r\lib\frei0r-1"
$ ffmpeg -i INPUT.mp4 -vf "frei0r=hogefugafilter" OUTPUT.mp4

ちなみにdllは https://dl.dropbox.com/s/10izo6dycp8as7b/mat33.dll に置いておきました。信用できない人はソースはgithubに上げたので自分でビルドしてみてください。 https://github.com/suzusuzu/frei0r/blob/mat33/src/filter/mat33/mat33.cpp

sobel filter

sobel filterとは空間1次微分を計算してedgeを抽出するfilterです。

上から下へのsobel filter 上から下へのsobel filter

左から右へのsobel filter 左から右へのsobel filter

ちなみにfilterは","で処理を繋げることができる。今回はsobelフィルターをかけるまえにグレースケールを行う

元動画 http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi

$ ffmpeg -t 30 -i http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi -vf "format=gray,frei0r=mat33:1|2|1|0|0|0|-1|-2|-1" -pix_fmt yuv420p sobel.mp4

}}}

平滑化 filter

平均化 filterとも言います。

名前の通り平らに滑らかにするfilterです。

$ ffmpeg -t 30 -i http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi -vf "frei0r=mat33:0.111|0.111|0.111|0.111|0.111|0.111|0.111|0.111|0.111" -pix_fmt yuv420p ave.mp4

}}}

MMA Advent Calendar 2016/12/13

そろそろブログまとめようと思ったので移転記事です.

移転元 https://wiki.mma.club.uec.ac.jp/su_zu/MMA%20AdventCalendar%202016

MMA Advent Calendar 2016/12/13

これはMMA Advent Calendar 2016の13日目の記事です

電気通信大学RSS「新着情報」

https://www.uec.ac.jp/index.rss

電気通信大学が学会での受賞や電気通信大学内で行うイベントなどその他もろもろの情報を発信しているRSSです。

私達電気通信大学生はもちろんこのRSSをチェックしたいですよね?でもブラウザの環境がない!!GUI環境が手元にない!!そんな時でも簡易的でもいいから電気通信大学RSSがみたいよおおおという需要に応える形でさくっと適当にそれなりに使えそうなものをOne-Linerで作ってみました。

ちなみにこのRSSのlinkタグの中身が "http://www.uec.ac.jp/news/announcement/hogefuga" だったり "/news/announcement/hogefuga" だったり統一されていないのに途中で気づいてOne-Linerを修正しました。

One-Liner

依存しているもの peco, xmllint, curl

pecoはRSS一覧から見たい記事を選択するインターフェイスとして使用します。xmllintはその名の通りxmlパーサーです。この2つをインストールしてください。

上の依存を見てなんだPOSIX互換じゃないのかよとかいう疑問を持ったと思いますが聞こえないふりをします。 ちなみにOne-Linerの定義とシェル芸の定義というものを以下のようであるとするならば間違いなく下記に記述するものはOne-Linerでありシェル芸です!!POSIX互換は関係ないのです!!そもそも通信系はcurlwgetかのPOSIX外コマンドに頼るしかない状況だからPOSIX原理主義者に何言われても動じない心を持っています。たまにcurlsendmailは例外だからという言葉を見るとなるほどなと思い、それなら「例外」という必殺技を僕も使いたいと思います。

仕様としてはRSS記事一覧から見たい記事を選択するとその記事のpタグを抜き出しているだけです。pタグだけ?ちゃんと整形して出力しろよという声が聞こえてくると思いますが聞こえないふりをします。少し言い訳をすると記事のフォーマットが一定ではないのでめんどくさいのと大体pタグさえ見れば記事の内容わかるだろうと雑に考えたからです。

curl  $(xmllint --xpath "//rss/channel/item[$(echo 'cat rss/channel/item/title' | xmllint --shell http://www.uec.ac.jp/index.rss | sed -n '/title/p' | sed -e 's/<title>\(.*\)<\/title>/\1/' | awk '{print NR, $0}' | peco | sed 's/^\([0-9]*\).*/\1/')]/link"  http://www.uec.ac.jp/index.rss | sed 's/<link>\(.*\)<\/link>/\1/' | awk '{if($1 ~ /http/) print; else print "http://www.uec.ac.jp" $1}') 2>/dev/null | xmllint --html --xpath '//p' 2>/dev/null - | sed 's/\(.*\)/\1\n/'

例:【報告】第4回電気通信大学Unique & Exciting Research Symposium ~研究力強化に向けた組織的な連携の在り方~

出力されたものは以下のようになります

<p><a id="pageTop"></a>このページの先頭です</p><p><a href="#contentTop">メニューを飛ばして本文を読む</a></p><p id="siteTtl"><a href="/"><img src="/common_rwd/images/pct_site-logo_pc.png" width="233" height="40" alt="国立大学法人 電気通信大学" class="switch"></a></p><p><a id="contentTop"></a>ここから本文です</p><p class="print">印刷機能を使用する場合はJavaScriptを有効にしてください。</p><p class="taRight">2016年12月07日</p><p>2016年12月2日(金)に本学B棟202教室にて、「第4回電気通信大学Unique &amp; Exciting Research Symposium」が開催されました。本シンポジウムは、文部科学省研究大学強化促進事業の一環として毎年開催されており、今年は、「研究力強化に向けた組織的な連携の在り方」とのテーマに関し、全国の大学、研究機関、民間企業等から約180名の参加がありました。</p><p>当日は、文部科学省大臣官房審議官(研究振興局担当)の板倉康洋氏のご来賓挨拶の後、パナソニック株式会社フェローの上野山 雄氏の講演「パナソニックにおける組織的な産学連携の取り組みと大学への期待」が行われました。その後、名古屋大学 学術研究・産学官連携推進本部副本部長の藤巻朗氏から「名古屋大学における研究力強化と組織的な連携の在り方」、また本学研究企画室副室長の森倉晋URAから「電通大における組織的な連携活動を加速するURAの取り組み」と題して、それぞれの大学における取り組みの紹介がありました。</p><p>「研究力強化に向けた組織的な連携の在り方」をテーマとするパネルディスカッションでは、講演者3名に加えて、福井大学 産学官連携研究開発機構URAオフィス副所長の山口光男氏にも参加して頂き、本学産学官連携センター長の中嶋信生特任教授の司会で、組織的な連携を進めるための繋ぐ機能やURAの役割に関して、会場の参加者との質疑討論を含めて活発な議論が行われました。</p><p>今後も引き続き学内外のネットワークの構築と活用を通じて、組織的な連携と協働の体制を構築することにより本学の研究力強化に向けて取り組んで参ります。</p><p class="toPageTop"><a href="#pageTop">TOP</a></p><p class="copyright"><span>Copyright © UEC Tokyo. All rights reserved.</span></p>

う〜ん見づらい。。。

MMA Advent Calendar 2016/12/6

そろそろブログまとめようと思ったので移転記事です.

移転元 https://wiki.mma.club.uec.ac.jp/su_zu/MMA%20AdventCalendar%202016

MMA Advent Calendar 2016/12/6

これはMMA Advent Calendar 2016の記事です

PowerShellでぐいぐいっとGUI動かす方法を紹介する。Widnows使っている人は気軽にPowerShellで実行してみて頂ければと思います。

先に言っておくが最近MSが頑張っていてLinuxでもPowerShellが動くがこれから行うものがバリバリ.NETに依存しているのでWindowsを用意してほしい。ちなみにWPFはWineでも対応していない。Windowsを宗教的理由で使えない方はまあできるんだ分かる分かるみたいな気持ちで見ていただければ幸いです。

サクッと.NET使いたいときはPowerShellが便利だと私は思っている。それならGUIも意外といけるのではと思いPowerShellGUIを動かしてみた 最初に結果を言ってしまうがまあできるが高機能なGUIはやはりしんどいし書いてて面倒くさくなったので当初Twitterクライアント作ろうかなと思ったがTwitter検索ツールに変更した。

WPF

WPFとはXAMLというXMLベースで書くことができるユーザーインターフェイス部分とロジック部分を分離してGUIを作成する仕組みです。WPF以前にはWindows Formsなどがあったが時代はXMLベースのGUI作成に流れが傾いている気がする(?)

まずXAMLを書く。そのまま書いてUIを組むのはしんどいのでVisual StudioとかBlendとかを作って頑張って欲しい。そしてそのXAMLを読み込んでwindowを作る。すると以下のようなものを作ることができる。

Add-Type -AssemblyName presentationframework


[xml]$xaml = @'
  <Window
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
          Title="mmaAdventCalendar" Height="350" Width="600">
      <StackPanel>
            <TextBlock FontSize="30" Text="炎炎炎!!!✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌"></TextBlock>
            <Image Source="http://d250g2.com/d250g2.jpg"></Image>
      </StackPanel>
  </Window>
'@

$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$window=[Windows.Markup.XamlReader]::Load( $reader )

$window.ShowDialog() | Out-Null

Twitter検索ツール

途中で飽きて雑なコードになっているのでまあこんなことできるよぐらいに思ってみてくれれば幸いです。

なぜか分からないが以下のスクリプトを一つのファイルにしてPowerShellで実行するとエラーがでる。最初にAdd-Type -AssemblyName presentationframeworkでDLL読み込んでから動かすと普通に動くので誰か教えて欲しい。

Add-Type -AssemblyName presentationframework

class Twi {
    static [xml]$xaml = @'
  <Window
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
          Title="mmaAdventCalendar" Height="350" Width="600">
      <Grid>
          <Grid.RowDefinitions>
              <RowDefinition Height="50"></RowDefinition>
              <RowDefinition></RowDefinition>
          </Grid.RowDefinitions>
          
          <Grid Grid.Row="0">
              <Grid.ColumnDefinitions>
                  <ColumnDefinition></ColumnDefinition>
                  <ColumnDefinition Width="50"></ColumnDefinition>
              </Grid.ColumnDefinitions>
              <TextBox Grid.Column="0" FontSize="30" Name="keyword"></TextBox>
              <Button Grid.Column="1" Name="search">search</Button>
          </Grid>

          <ScrollViewer Grid.Row="1">
              <Grid>
                  <Grid.RowDefinitions>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                      <RowDefinition Height="100"></RowDefinition>
                  </Grid.RowDefinitions>

                  <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="50"></ColumnDefinition>
                      <ColumnDefinition></ColumnDefinition>
                  </Grid.ColumnDefinitions>


                <Canvas Grid.Row="0" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img0"></Image>
                </Canvas>
                <Canvas Grid.Row="1" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img1"></Image>
                </Canvas>
                <Canvas Grid.Row="2" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img2"></Image>
                </Canvas>
                <Canvas Grid.Row="3" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img3"></Image>
                </Canvas>
                <Canvas Grid.Row="4" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img4"></Image>
                </Canvas>
                <Canvas Grid.Row="5" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img5"></Image>
                </Canvas>
                <Canvas Grid.Row="6" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img6"></Image>
                </Canvas>
                <Canvas Grid.Row="7" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img7"></Image>
                </Canvas>
                 <Canvas Grid.Row="8" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img8"></Image>
                </Canvas>
                <Canvas Grid.Row="9" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img9"></Image>
                </Canvas>
                <Canvas Grid.Row="10" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img10"></Image>
                </Canvas>
                <Canvas Grid.Row="11" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img11"></Image>
                </Canvas>
                <Canvas Grid.Row="12" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img12"></Image>
                </Canvas>
                <Canvas Grid.Row="13" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img13"></Image>
                </Canvas>
                <Canvas Grid.Row="14" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img14"></Image>
                </Canvas>
                <Canvas Grid.Row="15" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img15"></Image>
                </Canvas>
                <Canvas Grid.Row="16" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img16"></Image>
                </Canvas>
                <Canvas Grid.Row="17" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img17"></Image>
                </Canvas>
                <Canvas Grid.Row="18" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img18"></Image>
                </Canvas>
                <Canvas Grid.Row="19" Grid.Column="0">
                    <Image Width="50" Height="50" Name="img19"></Image>
                </Canvas>
 

                  <TextBox Grid.Row="0" Grid.Column="1" Name="text0" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="1" Grid.Column="1" Name="text1" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="2" Grid.Column="1" Name="text2" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="3" Grid.Column="1" Name="text3" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="4" Grid.Column="1" Name="text4" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="5" Grid.Column="1" Name="text5" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="6" Grid.Column="1" Name="text6" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="7" Grid.Column="1" Name="text7" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="8" Grid.Column="1" Name="text8" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="9" Grid.Column="1" Name="text9" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="10" Grid.Column="1" Name="text10" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="11" Grid.Column="1" Name="text11" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="12" Grid.Column="1" Name="text12" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="13" Grid.Column="1" Name="text13" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="14" Grid.Column="1" Name="text14" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="15" Grid.Column="1" Name="text15" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="16" Grid.Column="1" Name="text16" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="17" Grid.Column="1" Name="text17" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="18" Grid.Column="1" Name="text18" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  <TextBox Grid.Row="19" Grid.Column="1" Name="text19" IsReadOnly="True" TextWrapping="Wrap"></TextBox>
                  
              </Grid>
          </ScrollViewer>
      </Grid>
  </Window>
'@

[System.Windows.Controls.ContentControl]$window
[string]$consumer_key = "OlCmnCziFLdEe308ZvEJckX6U"
[string]$consumer_secret = "knoLolvTxQ1Had8jCcPbvWyD4lYt6f6anw27uAXmWc5GapNkId"
[Hashtable]$header
[System.Windows.Controls.Primitives.TextBoxBase]$keyword
[System.Windows.Controls.Primitives.ButtonBase]$search
[System.Windows.FrameworkElement[]]$imgs
[System.Windows.FrameworkElement[]]$texts
[System.Management.Automation.PSMethodInfo]$searched

 

    Twi(){
        $this.init()
    }

    Twi($consumer_key, $consumer_secret){
        $this.consumer_key = $consumer_key
        $this.consumer_secret = $consumer_secret
        $this.init()
    }

    init(){
        $this.imgs = New-Object System.Windows.FrameworkElement[] 20
        $this.texts = New-Object System.Windows.FrameworkElement[] 20

        $bearer = [Twi]::get_bearer($this.consumer_key, $this.consumer_secret)
        $this.header = @{
            "Authorization" = "Bearer " + $bearer;
        }

        $reader=(New-Object System.Xml.XmlNodeReader ([Twi]::xaml))
        $this.window=[Windows.Markup.XamlReader]::Load( $reader )

        for ($i=0; $i -lt 20; $i++){
            $this.imgs[$i] = $this.window.FindName("img" + $i.ToString())
            $this.texts[$i] = $this.window.FindName("text" + $i.ToString())
        }
        $this.keyword = $this.window.FindName("keyword")
        $this.search = $this.window.FindName("search")

        $this.keyword.Text = "UEC lang:ja"

        $this.searched = $this.search.add_Click

        $t = $this
        $this.searched.Invoke({
            $t.update()
        }) 

        $this.update()

        $this.window.ShowDialog()| Out-Null
    }

    [Object[]]getStatuses(){
        [string]$q = $this.keyword.Text
        $q = $q.Replace(" ", "+")
        $uri = "https://api.twitter.com/1.1/search/tweets.json?count=20&q=" + $q
        $response = Invoke-RestMethod -Method Get -Headers $this.header -Uri $uri
        return $response.statuses
    }

    update(){
        $statuses = $this.getStatuses()
        foreach ($status in $statuses){
            $index=$statuses.IndexOf($status)
            $this.imgs[$index].Source = $status.user.profile_image_url_https
            $this.texts[$index].Text = $status.text
        }

    }

    static [string]base64($str){
        $bytes = [System.Text.Encoding]::UTF8.GetBytes($str)
        return [System.Convert]::ToBase64String($bytes)
    }
    
    static [string]get_bearer($consumer_key, $consumer_secret){
    $basic = [Twi]::base64($consumer_key + ":" + $consumer_secret)
    $auth_header = @{
        "Authorization" = "Basic " + $basic;
        "Content-Type" = "application/x-www-form-urlencoded;charset=UTF-8"
    }

    $auth_body = "grant_type=client_credentials"

    $response = Invoke-RestMethod -Method Post -Headers $auth_header -Body $auth_body -Uri "https://api.twitter.com/oauth2/token"

    return $response.access_token;
    }
}

[Twi]::new()

MMA入って思うこと

みんなMMAに入って思うこと書いてる気がするので僕も書く。

最初にMMAの部室に行ったときは誰か覚えていないがSSHVPNの説明してもらって「苦しんで覚えるc言語」はいい本だよって教えてもらってすぐその時に生協に行って買って部室で読みながらコード書いていた気がする。そのあとAOJとか説いていってナップサック問題を自力で解こうとするが動的計画法を学んでこんなの自力で解けるわけなかったんだと時間を無駄にした感を味わってこれはしんどいなと思って一時期AOJやめてGUIとかLinuxの環境構築楽しんでいた気がする。当初MMAでのIDで呼び合う文化に抵抗がありあんまり気が進まなかったが環境に適応していっているのかわからないが今ではIDは分かるけど本名わからないが当たり前になってる。あとMMAに入りはじめのころは部員同士の「わかる!!」とか永遠手を手を叩ハイコンテクストな会話にもついていけなかったが今では分かるし分かりすぎるので人間なんとかなるもんだなぁと思う。

明日はbenevolent0505さんが記事を書いてくれるみたいですね。

STDP学習ベースのSNNでMNISTを分類する

雑に論文みて勉強したので何も保証しません.SNNの情報全然無いような気がするのでしんどい.

Spiking Neural Network(SNN)

ニューロンの活動電位(スパイク)に注目したニューラルネットワーク.現状,計算量が多いのでチップを作ったりなどのハードウェアの研究が盛んな傾向にあるような気がする.IBMTruneNorthとかIntelLoihiなどはSNNにあたる.

Spike-Timing-Dependent Plasticity(STDP)

STDPはスパイクタイミングに依存してシナプスの重みが変わる仕組みである. ざっくり言うと細胞Aが発火して,細胞Bが発火するとA->B間のシナプス結合が強まるLTP(長期増強)が起きて,逆に細胞Bが発火して,細胞Aが発火するとA->B間のシナプス結合が弱まるLTD(長期抑圧)が起きる.

シナプス前細胞の発火時間を{t_{pre}}シナプス後細胞の発火時間を{t_{post}}とする.{\Delta t}を以下のように定義する.

{\displaystyle
\Delta t = t_{pre} - t_{post}
}

シナプスの結合の重みの更新は以下の式で表される.STDPの式は色々提案されているが今回は基本的なものを使用する

stdp

ニューロンモデル

使用するニューロンモデルは積分発火モデルを使用する.

ネットワーク

入力はMNISTのそれぞれのピクセルデータを最大60Hzのポアソンスパイクモデルにして入力させる. よってneural codingはrate codingを使用する. 入力を受け取る興奮性の細胞が発火した場合,他の細胞を抑制させる(winner-take-all).

f:id:suzuzusu:20180416043913p:plain

学習後,最終的により多くの反応(発火回数)を示すニューロンをその教師ラベルと紐づける. テストでは,入力に対して最も多くの反応を示したニューロンを抽出し,そのニューロンと紐付けられているラベルと比較する.

結果

以下が学習させた900個のニューロンの重みを表した図である.

f:id:suzuzusu:20180418040907p:plain
weights

accuracy: 0.775

ソースコード

github.com

参考

Implementation of Poisson Spike model using Rust

自分用のメモ

Poisson Spike model(ポアソンスパイクモデル)

ある時間内に発火する頻度が,ポアソン分布に従うスパイクモデルである. 実際のニューロンは不応期などがあり,連続で発火することはないが,このモデルはその辺を考慮していない. ただ,大脳新皮質のスパイクはポアソンスパイクモデルと似たようなスパイクが観測されるらしい.

ポアソン分布は以下のような式で表される.

{\displaystyle
P(X=k) = \frac{\lambda^{k}e^{-\lambda}}{k!}
}

 \lambdaは平均回数を表す.

以下は,ポアソンスパイクモデルの実装

fn generate_spike(fr: f64, dt: f64, t: f64, rng: &mut XorShiftRng) -> Vec<usize> {
    // fr: 発火頻度 Hz
    // dt: 微小量
    // t: 生成する時系列の長さ sec
    let num = (t/dt) as usize;
    let v: Vec<usize> = rng.gen_iter().take(num).map(|x: f64| if x < fr*dt { 1 } else { 0 } ).collect(); // 1が発火を表す
    v
}

例えば 60\mathrm{Hz}の発火頻度のポアソンスパイクは1秒間に平均で60回発火が起きる.

以下で \lambda = 60ポアソン分布と1秒間に発火頻度 60\mathrm{Hz}ポアソンスパイクが発火した回数を比較した実験を行った.

extern crate gnuplot;
extern crate rand;

use rand::{Rng, XorShiftRng, SeedableRng};
use rand::distributions::{Poisson, Distribution};

use std::mem::transmute;


pub fn generate_spike(fr: f64, dt: f64, t: f64, rng: &mut XorShiftRng) -> Vec<usize> {
    let num = (t/dt) as usize;
    let v: Vec<usize> = rng.gen_iter().take(num).map(|x: f64| if x < fr*dt { 1 } else { 0 } ).collect();
    v
}

fn main() {
    let seed = 1;
    let x: u32 = 123456789;
    let y: u32 = 362436069;
    let z: u32 = 521288629;
    let w: u32 = seed;
    let seeds: [u32; 4] = [x, y, z, w];
    const N: usize = 1000000;
    const LAMBDA: f64 = 60.0;

    let seeds = unsafe {transmute(seeds)};
    let mut rng = XorShiftRng::from_seed(seeds);
    let mut fg = gnuplot::Figure::new();

    {
        // poisson spike
        let mut spike_cnts = Vec::with_capacity(N);
        for _ in 0..N {
            let spikes = generate_spike(LAMBDA, 0.0001, 1.0, &mut rng);
            let spike_cnt = spikes.iter().sum::<usize>();
            spike_cnts.push(spike_cnt);
        }

        let max_cnt = spike_cnts.iter().max().unwrap();
        let xs = (0..*max_cnt).collect::<Vec<usize>>();

        let mut spike_hist = vec![0;*max_cnt+1];
        for spike_cnt in &spike_cnts {
            spike_hist[*spike_cnt] += 1;
        }

        let ax = fg.axes2d();
        ax.lines(xs.iter(), spike_hist.iter(), &[gnuplot::Caption("poisson spike"), gnuplot::Color("blue")]);


        // poisson distributions
        let mut spike_cnts = Vec::with_capacity(N);
        for _ in 0..N {
            let poi = Poisson::new(LAMBDA);
            let v = poi.sample(&mut rng);
            spike_cnts.push(v);
        }
        let max_cnt = spike_cnts.iter().max().unwrap();

        let mut spike_hist = vec![0;(*max_cnt+1) as usize];
        for spike_cnt in &spike_cnts {
            spike_hist[*spike_cnt as usize] += 1;
        }

        ax.lines(xs.iter(), spike_hist.iter(), &[gnuplot::Caption("poisson distributions"), gnuplot::Color("red")]);

    }
    fg.echo_to_file("ps.plt");
}

f:id:suzuzusu:20180409042017p:plain
実行結果

良さそう.

github.com

参考