yensaki’s blog

必要なものは締め切り

プリティーシリーズ×Kubernetesの同人誌【技術書展8】

これは #プリッカソン Advent Calendar 2019 の15日目の記事です。
「プリパラ&キラッとプリ☆チャン Winter Live 2019」参加の方、お疲れさまでした

adventar.org

概要

Kubernetesの実践的な活用についてプリティーリズム・オールスターセレクションで紹介するマンガ同人誌を技術書展8で出します

Who?

サキ(yensaki)といいます。プリティーシリーズが好きなエンジニアです

技術面

好きなのはRuby on RailsRubyistです。

今年になってからKubernetesと広告エンジニアを始めました。
それまではサービス開発を長くやってきました。
好きなものは事業向け開発と安定リリース

プリティーシリーズ面

主に菱田正和の追っかけしています。
春音あいらが好きです。

イラストはちょっと描きますが目下修行中です

どんな本?

Kubernetesが気になって導入してみたいけどメリットや方法がよくわからないという人向けの入門本になる予定です。

私がKubernetesを始めて詰まったポイントや、実践で大事だと思ったことベースでデプロイ方法や開発方法を紹介する内容…?
オールスターセレクションのメンバーでそれの解説ができたらばハピラキ!

それはそれとして、オールスターセレクションはもう5年以上前でいろいろあやふやなので映像媒体出してほしいです

なんでKubernetes本?

  • やってて「Kuernetes難しいなー」って感じた
  • でも今後重要な技術だという確信も得た
  • 自分の中で整理しつつそれが誰かの役に立てば

なんでプリティーシリーズ?

プリティーシリーズが好きだからです。

そういえば来月は「KING OF PRISM ALL STARS -プリズムショー☆ベストテン-」が劇場公開されますね。
「劇場版プリティーリズム・プリズムショーベストテン」もオールスターセレクションの時期だったので感慨深いですね

おわり

技術書展8: 2日目
2020.03.01(日)@ 池袋サンシャインシティ

です! 配置情報は1ヶ月後。
技術書展初参加がんばりますよろしくのかしこま!

f:id:yensaki:20191215213719p:plain:w250

動画からセリフ起こし

What is ?

動画の中の音声をセリフ起こしするプロジェクト

例: レインボーライブ36話

まだ調整中だけどこんな感じ↓

f:id:yensaki:20190721234826p:plain
プリズム土下座

とか。

f:id:yensaki:20190721234829p:plain

とか。

目的

動画の音声をテキストで扱えるようにしたい。
ゆくゆくはセリフ検索からスクリーンショットを容易に取得できるようにする狙い。

How to

  • 動画の音声ファイルを無音部分でファイル分割
  • 分割ファイルごとにテキスト起こし

戦略

  1. 音声をテキストにする方法を検討
  2. 個人が機械学習でがんばっても効果は見込めないことを悟る
  3. 利用可能なものから選択
    • Google Cloud Speech to Text
    • Amazon Transcribe
    • Watson Speech to Text
    • Bing Speech API

精度、送信可能音声の長さ、使いやすさから Google Cloud Speech to Text を採択

cloud.google.com

無音部分でファイル分割

例えば24分の音声をそのまま一括でテキスト化はしにくいし、したくない。
ゆくゆくのセリフから検索をするには当該セリフが何秒から何秒までのものかを管理したい。
一括で文字起こしをするとそれを失う。

一番容易にできそうなのは sox だった

sox.sourceforge.net

数種類検証して全体音量の1%の状態が 0.3second 続いたら無音と認識するのがそこそこ良さそうだった(※まだ要調整)。

github.com

分割ファイルごとにテキスト起こし

  1. 分割ファイルがwavでなければwavに
  2. 分割ファイルごとにCloud Speech to Text APIで送信

残る課題

  • 各分割音声ファイルの秒数位置がわからない
    • 無音秒数をsoxで即時削除していて、そのままだと各分割音声ファイルが全体の何秒から何秒なのか計算できない
  • 動画から切り出した画像集とテキストの連携
    • テキストの秒数位置から対応する画像集をまとめられるはず
  • テキストから画像検索

まだYATTEIKI

Juucy - 真ん中似ている私達以外を cherry-picking -

Juucy

動画をアップロードすると「いいとこ取り」したキャプチャ集をつくるやつ

f:id:yensaki:20190407204736p:plain

f:id:yensaki:20190407204901p:plain   以下略

Why?

 

前回 CherryPickingMoments

yensaki.hatenablog.com  

  • Ruby のライブラリ cherry_picking_moments を作った
    • この名前すごく好きなので毎回推していきたい
    • 「瞬間をいいとこ取り」!
    • ちぇりぴき!
  • プxxxxxのキャプチャが欲しいから
  • 手元でコンソールすれば手に入るようになった

でもコンソールすら面倒だな?

アップロードしたらやってくれてもよくない?

(ソフトウェアでいいという説もある)

How

cherry_picking_moments は gem

  • rubygems 未公開
    • セットアップ手順整理したら公開したい
    • テストとCIも用意したいが公開を先にすべきかな…
  • pythonは必要だけど Python functions bridge の PyCall (gem) 使ってる

じゃあ Ruby on Rails でいいだろう

Juucy

juicy 真ん中似ている私達

いつかいつも cherry-picking days

そういうこと。

uu が双子果実みたい?

  1. 動画をアップロードしてS3へ
  2. 非同期で動画を CherryPickingMoments に渡す
  3. いいとこ取りでできた画像集もS3に送る
  4. ページ上で確認する!

やってたこと

  • 手元とheroku で雑に開発
  • heroku に python の buildpacks を追加しようとすると失敗
App not compatible with buildpack:
  • 最終的にはEC2にする予定だったのでここでherokuを切る
  • EC2の準備
    • 慣れてなかったので学習しながら準備中

課題

  • デザイン調整
    • bootstrap の途中で疲れた
  • ロゴ作成
    • juucy
  • ユーザー管理
    • devise 入れて途中までやったけど本質じゃなかったので保留してた
  • 実はS3結構お金かからない?(動画…, 何百件の画像...)
    • まぁたくさんの人使うわけじゃないでしょう

動画ファイルからいい感じに重複しない画像を取り出す

画像

画像は日常で使えたり使えなかったりして便利。 togetter.com

いろんなの使えたい

でも手元に画像はない

動画ファイルならあるんだけど。

じゃあ動画から画像を取り出せばいいのでは?

ffmpeg -i imovie.mp4 -ss 1 -vframes 1 -f image2 out.jpg

取り出したい画像を見つけて何回も繰り返すのは少しツラミ :smile:

動画から静止画を連続で

ffmpeg-r オプションを使えば連番で静止画を作成できる。

qiita.com

でも動画から一定間隔で取り出すと同じ画像、類似した画像もたくさんできる

これもまたツラミ :smile: 無駄が多くなっちゃう

なるべくユニークっぽく取り出してもらえない?

周辺探したところ、それができるものは見つからなかった。
ということでうまくできる方法を考える。
似てる画像がたくさんあるからツラミだとすればそれらを検知して消してくれればいいのでは?

イデア 1. 動画から一定間隔で静止画を取り出す 2. 静止画同士で類似画像度を判定して似てるやつらは消す

作った

github.com

名前が意外とハマって気に入った。
瞬間をいいとこ取り。

使用技術:

手順

  1. 動画ファイルから静止画を抽出
  2. 静止画をリサイズ
  3. 各画像から特徴を切り出してハッシュ値を算出(Perceptual Hash)
  4. それぞれを比較して類似画像を検出して削除

Perceptual Hash

Python の Imagehash を利用。
python便利…

一旦は phash を使用
画像間の類似度はハミング距離。

PyCall

その Python Imagehash は便利なんだけど
どうしても Ruby で全体を書きたい。

最初は Open3python を実行した。
でももっとちゃんとやりたくなったのでもう少し考える。
Ruby から Python function を実行できる PyCall があるのでそれを使いたい。
ちゃんと乗っておくと後々楽そうなので。

GitHub - mrkn/pycall.rb: Calling Python functions from the Ruby language

というわけで最終的には全部 Ruby ファイルで完結できた。
ハミング距離の計算もRuby で。

こんな感じ

24分程度のmp4を渡すと30分ぐらいで画像集ができた。
2/3ぐらいは 切り出しと convert の時間だった。
imagehash の算出/ハミング距離の計算/ファイル削除はせいぜい10分程度。

f:id:yensaki:20181202174726p:plain

3 Pictures/s で静止画を取っていたので24分は4300枚。 ハミング距離20までを類似として扱うと3500枚ほど削除できる。

まとめ

Ruby のライブラリで 動画から類似画像を(なるべく)除いた画像を切り出せるようになりました。
消しすぎ・残しすぎがまだいくらかあるのでもう一歩調整できる。
Python と PyCall に感謝。

RubyKaigi 2018 型の話のまとめ

RubyKaigi 2018 では型についてのセッションがいくつかあり、個人的になるほどと思いながら色々考える機会になりました。
ざっくりここでまとめます。

matz KeyNote 質疑応答

質問者: 最近、TypeScript など静的型付けが流行ってるのが個人的に腹が立っている。 でもJavaScriptよりはTypeScriptがいいと思っている。 Ruby に今後、静的型付けという概念が入りますか?

Matz: まずRubyは今後も静的型付けを入れる事はないです。 型があった方が便利なケースは確かにある。例えばコンパイル時に判定できるなど。 でも十分に賢い人間であれば大きくないソフトウェアであれば型を推測することができると思います。 人間にできるということは未来では優秀なコンピュータなら型宣言がなくても型を推測することができるようになるのでは? 2010年台、2020年台、今は型宣言がとても効果的なのかもしれない。 でも2030年、2040年には自動型推論が主流になって、型宣言が古めかしいものになるかもしれない。


トレンドに逆らってまで頑なに型宣言を入れるつもりがないモチベーションを知ることができた気がします。

どこかで matz さんが言ってたと思うのですが 「機械に合わせて面倒なことをしたくない。機械に面倒なことをさせたい。」みたいな話かなと。

※免責: 発言そのまま書き起こしではありません。 ニュアンスなど多々違います

Steep

https://github.com/soutaro/steep

https://speakerdeck.com/soutaro/ruby-programming-with-type-checking

  • sig/*.rbi に定義を置く
  • 実装と定義ファイルを比較してチェック
  • 実装から定義ファイルの scaffold を作成できる
  • Rails のようなメタプログラミングには効きにくい

 

Usage

以下 https://github.com/soutaro/steep の README より抜粋

 

class Person
  @name: String
  @contacts: Array<Email | Phone>

  def initialize: (name: String) -> any
  def name: -> String
  def contacts: -> Array<Email | Phone>
  def guess_country: -> (String | nil)
end

class Email
  @address: String

  def initialize: (address: String) -> any
  def address: -> String
end

class Phone
  @country: String
  @number: String

  def initialize: (country: String, number: String) -> any
  def country: -> String
  def number: -> String

  def self.countries: -> Hash<String, String>
end
class Person
  # `@dynamic` annotation is to tell steep that
  # the `name` and `contacts` methods are defined without def syntax.
  # (Steep can skip checking if the methods are implemented.)

  # @dynamic name, contacts
  attr_reader :name
  attr_reader :contacts

  def initialize(name:)
    @name = name
    @contacts = []
  end

  def guess_country()
    contacts.map do |contact|
      # With case expression, simple type-case is implemented.
      # `contact` has type of `Phone | Email` but in the `when` clause, contact has type of `Phone`.
      case contact
      when Phone
        contact.country
      end
    end.compact.first
  end
end

class Email
  # @dynamic address
  attr_reader :address

  def initialize(address:)
    @address = address
  end

  def ==(other)
    # `other` has type of `any`, which means type checking is skipped.
    # No type errors can be detected in this method.
    other.is_a?(self.class) && other.address == address
  end

  def hash
    self.class.hash ^ address.hash
  end
end

class Phone
  # @dynamic country, number

  def initialize(country:, number:)
    @country = country
    @number = number
  end

  def ==(other)
    # You cannot use `case` for type case because `other` has type of `any`, not a union type.
    # You have to explicitly declare the type of `other` in `if` expression.

    if other.is_a?(Phone)
      # @type var other: Phone
      other.country == country && other.number == number
    end
  end

  def hash<i></i>
    self.class.hash ^ country.hash ^ number.hash
  end
end
  • attr_reader など解釈されない定義は @dynamic で指定して解決する

Type Check

実装が型定義から外れていないかチェックできる

$ steep check lib
lib/phone.rb:46:0: MethodDefinitionMissing: module=::Phone, method=self.countries (class Phone)

Scaffolding

実装から型定義の枠組みを作成できる

$ steep scaffold lib/*.rb

Type Profiler

Endoh さんセッション

  • matz 曰く static type check で annotation は別ファイルが希望
  • Type DB
    • 複数の Type Profiler を集めて推定する
  • Type Profiler
    • 厳密な type interface は無理
    • 大分して静的な解析, 実行時解析

感想

前年も型についてはセッションがありましたが、より具体的な方向性が見えてきたように思います。 Ruby の楽しさを失わずに型と仲良くできる道、とても楽しそう。

サービス開発フローのメモ

個人でサービス開発しようと思ったので それにあたって思考の過程を整理して業務等の開発マネジメントに役立ててみるテスト。

イメージは1人で プロジェクトマネージャー、エンジニア、デザイナー、サポートをやる感じ。

サービス開発を始めるにあたって考えたこと

どうやったらスムーズに開発ができるか。 プロジェクトマネジメントには様々な考え方や手法があるがどれをどのタイミングで活用すべきか。 迷いそうなので今私が知っている手法と経験から進めてみることにします。

Why-How-What, インセプションデッキに関心があるのでそれを踏まえつつプロセスを整理してみます。

Why-How-What

私が一番理念として置いているのが Why-How-What なのでこれを大前提にする。 https://www.ted.com/talks/simon_sinek_how_great_leaders_inspire_action?language=ja

何か価値を出したいからサービスを開発するし、価値を出すから使ってもらえる。 ではどんな価値を出したいのか。 Why、理由、目的、信念。 これをきちんと決めていく。

インセプションデッキ

ささっとできるものならいいですが、 そうでもないならばプロジェクトがどういうものかぼんやりしないよう、 インセプションデッキを組んで全体像を整理します。

https://agilewarrior.wordpress.com/2010/11/06/the-agile-inception-deck/

開発プロセス

多分どこかで見直しますが現時点で考えてるのはこんな感じの順番

  1. 目的の認識合わせ
  2. 方針の決定
  3. 大まかな実現方法の決定
  4. 期間とコアチームメンバーの決定
  5. QCDS バランスの決定

目的の認識合わせ

  • プロジェクトの Why を全員で共有する。
  • 代表者だけが認識していると他の人は違う目的で動く可能性がある
    • 後半になって全く違う方向性で開発が進んでしまう恐れ
  • インセプションデッキ: Why Are We Here? を埋める

方針の決定

  • 目的を達成するにあたって何を重視していくか等
  • サービスの特徴
  • サービスの魅力
  • インセプションデッキ: Elevator Pitch を埋める

大まかな実現方法の決定

決めた方針に対してどういう手法を取るか。 基本的にはおよそ決まってるとは思うが他のアイデアはないか念押し確認。認識共有。 後からもっといい実現方法が出てきたり、設計が終わった頃合いにチーム内で実現方法の認識ズレが発生するのを防ぐ

手書きでもデザインモックでもなんでもいいのでサービスイメージを添えたい

期間とコアメンバーの決定

プロジェクト規模を確認する。 実現方法が決まっていればおよその規模感を図ることはできそう。 例えば1ヶ月ぐらいでやるのか、3ヶ月ぐらいでやるのか。 例えばAチームの7人でやるのか Aチームの7人の他、Bチームの◯◯に詳しい2人が参加してやるのか。

たいていズレるだろうが規模感の認識を持つことを主点とする。 「ディレクターは1ヶ月でできるぐらいにしたいと思っていたのにエンジニアはいつの間にか2ヶ月ぐらいの規模感で設計していた」とか 「当然Dさんはプロジェクトに参加するのだろうと思っていたのに他のプロジェクトに参加していた」とかが起きないように。

QCDS バランスの決定

実現方法、期間、コアメンバーがおよそ決まったら QCDS で何を重視するか判断する材料は揃っていそう。 主に確認すべきことは下記。Quality, Cost はそうそう調整するような要素として挙がらないのが経験上。 Quality は(金銭関係のシステムで)ミスできない、といったものはあるがCDSに影響を与えるのかまだ疑問。

  • 納期は調整できるか
    • できる場合はその条件, 程度
    • できない場合はその理由
  • ファーストリリースでの最低限はどのあたりか

続き

続く。