stMind

about Tech, Computer vision and Machine learning

CourseraのNLP in tensorflowを見てSentiment Analysisが容易に出来ると知る

www.coursera.org

tensorflow_datasetに用意されているimdb_reviewsデータセットを取得して、kerasのTokenizerを使って前処理して、Modelを書いて、学習。

これをテンプレートとして使えば、EmbeddingはBERTに変えたり、imdb_reviewsを自分で作ったデータセットにしたりして、拡張していけそう。

import tensorflow_datasets as tfds
import numpy as np

from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
import tensorflow as tf

if __name__ == "__main__":
    # 1. Load imdb dataset
    imdb, info = tfds.load('imdb_reviews', with_info=True, as_supervised=True)

    # 2. Split imdb dataset into train / test data
    train_data, test_data = imdb['train'], imdb['test']

    # 3. Prepare sentences and labels
    training_sentences = []
    training_labels = []

    testing_sentences = []
    testing_labels = []

    for s, l in train_data:
        training_sentences.append(str(s.numpy()))
        training_labels.append(l.numpy())

    for s, l in test_data:
        testing_sentences.append(str(s.numpy()))
        testing_labels.append(l.numpy())

    training_labels = np.array(training_labels)
    testing_labels = np.array(testing_labels)

    # 4. Hyperparameters
    vocab_size = 10000
    embedding_dim = 16
    max_length = 120
    trunc_type = 'post'
    oov_token = '<OOV>'

    # 5. Tokenize
    tokenizer = Tokenizer(num_words=vocab_size, oov_token=oov_token)
    tokenizer.fit_on_texts(training_sentences)
    word_index = tokenizer.word_index
    sequences = tokenizer.texts_to_sequences(training_sentences)
    padded = pad_sequences(sequences, maxlen=max_length, truncating=trunc_type)

    testing_sequences = tokenizer.texts_to_sequences(testing_sentences)
    testing_padded = pad_sequences(testing_sequences, maxlen=max_length, truncating=trunc_type)

    # 6. Defining model
    model = tf.keras.Sequential([
        tf.keras.layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(6, activation='relu'),
        tf.keras.layers.Dense(1, activation='sigmoid')
    ])

    # 7. Compile and training
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    model.summary()

    num_epochs = 10
    model.fit(padded, training_labels, epochs=num_epochs, validation_data=(testing_padded, testing_labels))
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, 120, 16)           160000    
_________________________________________________________________
flatten_1 (Flatten)          (None, 1920)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 6)                 11526     
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 7         
=================================================================
Total params: 171,533
Trainable params: 171,533
Non-trainable params: 0
_________________________________________________________________
Epoch 1/10
782/782 [==============================] - 4s 5ms/step - loss: 0.5723 - accuracy: 0.7062 - val_loss: 0.4707 - val_accuracy: 0.8163
Epoch 2/10
782/782 [==============================] - 4s 5ms/step - loss: 0.3454 - accuracy: 0.8918 - val_loss: 0.4481 - val_accuracy: 0.8147
Epoch 3/10
782/782 [==============================] - 4s 5ms/step - loss: 0.1946 - accuracy: 0.9558 - val_loss: 0.5217 - val_accuracy: 0.8035
Epoch 4/10
782/782 [==============================] - 4s 5ms/step - loss: 0.1172 - accuracy: 0.9798 - val_loss: 0.5584 - val_accuracy: 0.8052
Epoch 5/10
782/782 [==============================] - 4s 5ms/step - loss: 0.0851 - accuracy: 0.9852 - val_loss: 0.6381 - val_accuracy: 0.8047
Epoch 6/10
782/782 [==============================] - 4s 5ms/step - loss: 0.0707 - accuracy: 0.9869 - val_loss: 0.6734 - val_accuracy: 0.8055
Epoch 7/10
782/782 [==============================] - 4s 5ms/step - loss: 0.0643 - accuracy: 0.9872 - val_loss: 0.7113 - val_accuracy: 0.8036
Epoch 8/10
782/782 [==============================] - 4s 5ms/step - loss: 0.0598 - accuracy: 0.9879 - val_loss: 0.7544 - val_accuracy: 0.8028
Epoch 9/10
782/782 [==============================] - 4s 5ms/step - loss: 0.0568 - accuracy: 0.9883 - val_loss: 0.7722 - val_accuracy: 0.8052
Epoch 10/10
782/782 [==============================] - 4s 5ms/step - loss: 0.0558 - accuracy: 0.9884 - val_loss: 0.8033 - val_accuracy: 0.8050

github.com

Tensorflowレポジトリのコミット数ランキングを表示するワンライナー

  1. git logコマンドのfomatオプションでauthor nameを出力
  2. sort
  3. uniq -cで連続する行数をカウント、重複行は削除
  4. sort -nrで降順にソート
  5. headで先頭から10件表示
$ git log --format='%an' | sort | uniq -c | sort -nr | head 
21995 A. Unique TensorFlower
3476 TensorFlower Gardener
1229 Yong Tang
1155 Shanqing Cai
1154 Derek Murray
1055 Gunhan Gulsoy
1046 Benoit Steiner
1036 Vijay Vasudevan
 865 River Riddle
 794 Martin Wicke

tensorflowのレポジトリをローカルに持ってない場合は、Github APIを使ってコミット履歴を取ってくる。(Pageを解釈するのはちょっと難しかったので置いといて...)

  1. wgetでcommitsをJSONで受け取る
  2. jqでjsonのauthor nameを抽出
  3. 上で実行した2以降の処理をする
$ wget -O - -q https://api.github.com/repos/tensorflow/tensorflow/commits?per_page=100 | jq '.[] | .commit.author.name' | sort | uniq -c | sort -nr | head
  16 "A. Unique TensorFlower"
   8 "TensorFlower Gardener"
   5 "Gunhan Gulsoy"
   4 "Yujing Zhang"
   3 "Zhenyu Tan"
   3 "Peter Hawkins"
   3 "Andy Ly"
   2 "tg-at-google"
   2 "Thomas O'Malley"
   2 "T.J. Alumbaugh"

以下のブログにインスパイアされてやってみました。

prithu.xyz

画像からの料理名推定

blog.stratospark.com

2017年なので少し前になりますが、画像から料理名を推定するプロジェクト。

InceptionV3のImageNet pre-trainedのモデルをFine tuningして、Food 101データセットで82.03% @ Top-1の精度が出たようです。

Food 101は、名前の通り101クラスで、各クラス1000画像含まれているので、メモリ上に展開すると80GB程度になるらしい。96GBのメモリを積んだマシンを使ったらしいが、これは富豪アプローチですね...

Data augmentationは、KerasのImageDataGeneratorで、 rotation_range、width_shift_range、height_shift_range、horizontal_flip、zoom_range、channel_shift_rangeあたりが使われてます。

学習は初期トライアルではAdamやAdaGradで試してたが、最終的にはSGDで学習。

ここから精度を上げるのは反復トライアルが必要な難しいタスクになりそうですが、スタート地点のBaselineとして使える気がします。

Baidu researchが作ったテキストからビデオを作成する技術

blog.deeplearning.ai

deeplearning.aiが発行しているnewsletterにあったVidPress。

URLを入力とすると、最初にWebページの内容を解析して、関連する記事も収集(解析には、Ernieというモデルが使われているよう)。 その後、テキストサマリを作成、サマリに関する合成音声を作成するのと、サマリに合う映像クリップを収集して、最後に映像と音声をアラインメントして出力する。

65%のユーザは、VidPressが作成したビデオを最後まで視聴したが、人が作成したビデオは途中で視聴をやめることが多かったという結果が得られたらしい。

これが未来のサッカー観戦か!Zoomでバーチャルスタンド

www.bbc.com

これからの時代のサッカー観戦はこうなるのかもしれない!

デンマークで行われたリーグ戦、当然ながら現地にファンはいないのだけど、スタジアムに設置された巨大スクリーンにはZoomにログインしたファンの姿が!!(動画は下のURLから)

https://www.espn.com/soccer/danish-sas-ligaen/story/4103225/danish-superliga-returns-in-front-of-supporters-on-zoom

40x2.8mのスクリーンに約200人のファンが映し出され、合計で1万人のファンがリアルタイムに観戦したようです。リモートとはいえ、選手はファンのリアクションが感じられるし、ファンも現地にいるような感覚になれるし、とても良い仕組みだと思う。

プレミアリーグも6月17日に再開されるようだし、感染拡大を予防しつつ、新しい体験を提供する仕組みづくりに取り組んでほしいなと思う。

Scene text detection/recognitionのためのTotal text dataset

GitHub - cs-chan/Total-Text-Dataset: Total Text Dataset. It consists of 1555 images with more than 3 different text orientations: Horizontal, Multi-Oriented, and Curved, one of a kind.

coco-textに対して40分の1くらいの画像数ですが、curved textのground truthを含むTotal-Text-Dataset。

アノテーションデータは、ここからダウンロード出来ます。 また、画像はこちらからダウンロード出来ます。

アノテーションはmatファイルで、下記のフォーマットで提供されています。

  • Column 1-2 = X-coordinate
  • Column 3-4 = Y-coordinate
  • Column 5 = Text
  • Column 6 = Orientation (c=curve; h=horizontal; m=multi-oriented; #=dont care)

画像に表示して確認してみました。下記のコードをipythonなどで実行すれば、別の画像にも同じように出来るはずです。

In [1]: import cv2

In [2]: import scipy.io as sio

In [3]: import numpy as np

In [4]: data = sio.loadmat('gt_img13.mat')

In [5]: img = cv2.imread('img13.jpg')

In [6]: for i in range(data['gt'].shape[0]):
   ...:     points = np.array([(x, y) for x, y in zip(data['gt'][i][1][0], data['gt'][i][3][0])], dtype=np.int32)
   ...:     cv2.polylines(img, [points], isClosed=True, color=(0, 255, 0), thickness=3)
   ...:     

In [7]: cv2.imshow('TEST', img)

In [8]: cv2.waitKey(0)

In [9]: cv2.destroyAllWindows()

f:id:satojkovic:20200528221125j:plain

ICCV2017の論文、Revisiting IM2GPS in the Deep Learning Era

論文を読むのがそれなりの速度で行えるようになってきた。せっかくなので、読んでいるものをこのブログにまとめていこうと思う。 といっても、詳細に入るのではなく、主にAbstractとIntroduction、代表図面のあたりのまとめで、従来手法の課題や著者のアプローチの概要を把握した内容にする。

まずは、タイトルに有るように、画像から地理位置情報を推定するタスクに関する論文。

Introduction

メタデータの付与されてない一枚の画像から位置を推定するのは、相当難しい。 そこで、クエリ画像に対してGPS座標を推定するタスクと考える。 GPS座標であれば、アプリケーションにも依るが、ある閾値以内で推定成功と判定する事ができる。

このとき考えられる手法の一つは、データベースに含まれる位置の既知な画像の中から、クエリ画像と一致する画像を局所特徴マッチングで検索するアプローチ。 ただし、このアプローチが機能するのは、

  1. データベースに含まれる画像とクエリ画像が、比較的近い見え方であること
  2. クエリ画像にランドマークとなるようなコンテンツが含まれていて、局所特徴マッチングしやすい が条件。

とはいえ、これらが成り立つことは想定できないことが多いので、局所特徴マッチングに頼らないアプローチが必要。

従来手法と課題

Im2GPSでは、Instance recognitionとScene recognitionの論文で使わたHand-craftedな特徴量を導入して、instance levelなマッチング(「ギリシャアテネにある建物」というレベル)による方法を提案した。

PlaNetでは、地球表面を細分化して、細分化したクラスの分類問題として定式化。画像からクラスの確率分布を出力するCNN(細分化した各クラスのメタデータがついた画像を用いた学習)を使うことで、大きな精度向上を果たした。

PlaNetの方法の課題は

  1. 得られる位置精度が粗い(もっと細かい位置を本当は知りたい)
  2. CNNで直接クラス分類するのは難しいタスク

アプローチ

この論文では、上記二つを併用して性能向上を目指した。実際に、PlaNetに対して+10%以上の性能向上が出来て、Deep featureの利用とこの特徴量による画像検索の構成にしたことによるものと考察してる。

f:id:satojkovic:20200527213001p:plain

Reference

Revisiting IM2GPS in the Deep Learning Era: https://arxiv.org/pdf/1705.04838.pdf