ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

ルクミーMIMAMORIフォントを作ってみる

Webエンジニアのほんまです。

今回ですが、紹介できるネタがなくなってしまったので、ちょっとお遊び的な内容になっています。 エンジニアの方には物足りないかもですが、非エンジニアの方は楽しめる内容になっていると思いますよ。

今回は、「ルクミーMIMAMORIフォントの作成」にチャレンジしてみました。

続きを読む

ユニファのシステムの移り変わり(後編)

おはこんにちばんは! ユニファのインフラ見てますすずきです。

とりあえずユニファシステム遍歴の最後、後編です。
今現在では新サービス、新サブシステムが増えたり、微妙に構成変更したりしていますが一旦は昨年のフォトリニューアルのタイミングまでを後半としようと思います。

前編、中編はこちら

tech.unifa-e.com tech.unifa-e.com

さっそく後編始めます。

続きを読む

ユニファのシステムの移り変わり(中編)

おはこんにちばんは! ユニファのインフラ見てますすずきです。

先週に引き続き書いています。(ホントはこれも先週出す予定…)
引き続きなので今回はユニファのシステム変化の中編(後編では収まらなさそうだ…

前編はこちら

tech.unifa-e.com

さっそく中編始めます。

続きを読む

RSGT2020 参加レポート

こんにちは。スクラムマスターの渡部です。

まだまだスクラムマスターとしての経験が浅い私ですが、幸運にもRSGT2020に参加させていただくことができたので、ここにまとめたいと思います。

あらゆるセッション、あらゆる出会いと体験が素晴らしいものでした。

ですので、その全てに触れるのはここでは諦めます。 今回の記事では、特に印象に残ったこといまのチーム・組織に活かせそうなこと考える必要がありそうなことにフォーカスします。

社外の方はもちろんですが、社内の方にも見ていただきたい内容に、きっとなっていると思います。

RSGT2020とは

RSGT2020と略称を連呼していますが、正式にはRegional Scrum Gathering Tokyo 2020(リージョナル スクラム ギャザリング 東京)と言います。

2020.scrumgatheringtokyo.org

アジャイル / スクラムに関わる方が400人ほど集まり、スクラム開発の成功 / 失敗体験の共有や、スクラムを理解する助けになるようなお話、理想に向かって進むときの問題と必要なアプローチなど、様々なテーマのセッションが行われます。

また、参加されている方はみな、各々の現場でより良いチーム、良いプロダクト、良い組織のために悩み抜いていらっしゃる方ばかりなので、セッション外の時間でのコミュニケーションからも多くの学びを得られる、ワクワクが満載のイベントでした。

因みに私は、(恐らく無関係な)複数の方から「まだまだコントロールしようとしている」という趣旨の指摘を受けています。「難し〜!!」と心の中で叫びつつも、その通りだと理解しているので、今後の課題の一つとして認識しています。

…これでもちょっと意識しているつもりなんですが、本当に難しいんですよ!!!(大泣)

雰囲気

会場

f:id:unifa_tech:20200203184429j:plain
会場となったソラシティカンファレンスセンター

f:id:unifa_tech:20200203162932j:plain
セッションが行われる場所

前回までは別の開催場所だったようですが、今回は御茶ノ水にあるソラシティカンファレンスセンター*1で開催されました。

会場は、写真ではちょっと伝わりにくいのですがかなり広く、多分400名くらい入ると思います。また、写真の部屋の他にもう一会場ありますので、かなり規模が大きいことがわかるかと思います。

積極的な採用活動

f:id:unifa_tech:20200203184518p:plain
一緒に保育をハックするプロダクトを作りたい方、募集中!!

ロビースペースにはジョブボードが張り出され、皆さんの会社が一言コメント付きで募集をかけていました。当然弊社も参加しています。

興味がある方はぜひ一度ご連絡ください(笑)

herp.careers

おすすめのAgile / Scrum本アンケート

ロビーの壁に投票用紙があり、参加者のおすすめ本アンケートが行われていました。

iwakiri.hatenablog.com

詳細な結果は上記リンクをご覧いただければと思いますが、良書と言われている本はやはり強いですね。「アジャイルサムライ」は全参加者層から1位を獲得していたようです。

他の本もほとんどは見聞きしたラインナップでしたが、「Joy,Inc.」のみ知らず…個人的にAmazonで購入したのはまた別のお話です。

以下、セッションについての感想です。

良い悪いではない。あなたはいま、どの段階なのか?

confengine.com

1日目のKeynoteでは、スクラムを「禅の入門書」に照らし合わせて、(言い方に語弊があるかもしれませんが)初心者から熟練者までのそれぞれのフェーズを解説する内容でした。

その中で都度「いまのあなたはどの段階ですか?良い悪いではありません、いまの段階を知ることが重要です」と話されていたことが、非常に印象的でした。

「段階をすっ飛ばして一気に理想を追い求めるべきではない、まずは正しく現状把握をせよ。そして次の段階へ進むために必要な適切な行動をすべし。」

そう言われているように感じ、プレッシャーとともに、勇気をもらえたような気がしました。(そう思えるようになったのは2日目以降でしたが)

何をするにしても、理想と現状の間にはギャップがあります。それはスクラムに限らず、個人のスキル、チームの状態、あらゆることに当てはまります。

大事なのは、いま私たちがどの段階にいるのかを理解すること。そして、次の段階に進むために何が不足しているかを考え、一歩一歩前進していくことなのです。

会社やチームのことを、めっちゃ嬉しそうに語れるか?

Tadahiro Yasuda - 日本にJoy,Incを創る!ぼくらのジョイインクジャーニー3年間の軌跡

www.slideshare.net

おすすめのAgile / Scrum本で見事第二位を獲得した、話題のあの本が関連するお話です。

発表されていた会社は、昔は会議が暗い雰囲気で、チーム間でいがみ合いがあったり、業績も良くなかったそうです。(そんなことを声を大にして発表するなんて、非常に勇気がいることだったと思います)

そんな時にJoy,Inc. *2に出会い(恐らく憧れを抱き)、チームを、会社を変えるために行ってきた施策とその効果が紹介されていました。

その中でも比較的簡単に導入できて、特に面白そうだったものを紹介したいと思います。

ふるふるリレートーク

輪になって順番にリレートークするのですが、誰か一人を「ふるふると震えるほど」褒めまくるとのこと。

単純に面白そう、ということもありますが、忘れられがちな良いところを言語化して話すことで、聞いてる人もその人を知ることができますし、言われる側も改めて何が貢献できているかを理解できるのは素晴らしいですね。

チームの他の人が自分に対して何を期待しているのか、何をしてもらったら嬉しいのかは、わかっているように思えて、実は少しずつずれているものです。

そういったミスコミュニケーションを減らせるので、日々の仕事の効率も少しずつ上がっていきそうな気もします。やってみたいですね。

雑談

合間合間で積極的にコミュニケーションできるよう心がけていたのですが、まさか「雑談だけの時間」を作ってしまうとは驚きでした。

改めて考えてみると、「効果がある」とされていることを、業務時間で取り入れていけない訳が無いんですよね。

ただ、続けていくと話す人が偏ったり、ネタ切れになったりと課題はあったらしく、こころかるた*3というものを使って解消されていたそうです。

詳しいやり方、やってみた効果のまとめはこちらにあるので、よければご覧になってみてください。 www.creationline.com

カルチャーと業績は連動する

私たちは同じ会社で一緒に働いてはいますが、意識的に相手を理解しようと努めないと、仕事のアウトプット以外はよく知らないなんて状態になります。 そうなると、心理的安全性*4も低い状態になり、生産性も低下していくのでしょう。

セッションでは、「繋がりができて仕事がスムーズになった」、「心理的安全性が高まった」ということが強調されていました。

心理的安全性はパフォーマンスに繋がりますからね、素晴らしい!

そして、上記のような施策を実施し、カルチャーをカイゼンし続けた結果、従業員のエンゲージメントスコア会社の業績が連動して上昇したという結果が出たそうです。

「ふるふるリレートーク」も「雑談」も、時間さえ確保できればカンタンに実践できるので、私も早速取り入れてみたいと思います。皆様も是非!

最後に

参加された方のブログもたくさん拝見したところ、みなさん「ブログでは書ききれない」「学びの多い時間」「勇気をもらえた」と口を揃えて仰っていますが、本当にその通りでした(笑)

今も昔も悩みだらけですが、一つ違うのは、「自分だけではなく、みんなも同じように理想と現実とのギャップに悩みながら、明日が少しでも幸せになるように足掻いていることを知った」という点です。

RSGTに参加したからと言ってすぐさま劇的に状況が変化することはありませんが、今スプリントよりちょっとだけ素敵な来スプリントへ向かって、一歩一歩着実に、楽しく、勇気を持って進んでいきたいと思います。そんなチームに、会社になっていけるよう、引き続き精進していきたいと思います。

最後の最後になりましたが、RSGT2020参加者・関係者・スポンサー企業の皆様、そして、快く送り出してくれたチームのみんなに感謝を。

f:id:unifa_tech:20200203175248j:plain
スポンサーロゴ

Pytorch Tiny Edge Detection

By Matthew Millar R&D Scientist at ユニファ

Purpose

This blog will show how to make a custom edge detector using a very small Convolutional Network and Pytorch. This will be a very simple approach to making a fast and accurate Edge detector which is better than Opencv Canny Edge Detector.

Edge Detection

Edge detection is a basic computer vision technique that allows for the edges or boundaries of an image to be found. This is one of the basic methods for CV that most people do when they start using OpenCV as their Canny edge is fairly good, but will have to be worked over several times to find the optimal parameters per image which cannot be applied to every image that is processed. That is where CNN can help out.

CNN for edge detection

CNNs are very good at extracting features from an image. These features can then be used to generate edges of the image. The process starts by reading in an image then converting it to a grayscale image. To get good results, building out your own filters would be best, but for ok results using a very basic filter can be used. Then using these filters in CNN as the kernel size will allow for the extraction of features from the image. The activation layer (normally Relu) will give you the black and white extraction that you would expect.

Let's walk through the Code.

The imports you will need

import cv2
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

Using a photo I took from an American Air Show in Japan we will show how to work with Pytorch and edge detection from scratch.

f:id:unifa_tech:20200129153649j:plain
F-18
Next we will read in the image and transform it into a grayscale image.

img_path = 'data/f18.jpg'
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = gray.astype('float32')/255
plt.imshow(gray, cmap='gray')
plt.show()

Next we need to define our filters which will do the feature extraction in the CNN

# Vizulization filters
base_filter = np.array([[-1, -1, 1, 1], [-1, -1, 1, 1], [-1, -1, 1, 1], [-1, -1, 1, 1]])
print("Filers: ", base_filter.shape)
# Defining four different filters, 
# all of which are linear combinations of the `filter_vals` defined above

# define four filters
filter_1 = base_filter
filter_2 = -filter_1
filter_3 = filter_1.T
filter_4 = -filter_3
filters = np.array([filter_1, filter_2, filter_3, filter_4])
print('Filter 1: \n', filter_1)

Here is what the filters will look like in Numpy

Filers:  (4, 4)
Filter 1: 
 [[-1 -1  1  1]
 [-1 -1  1  1]
 [-1 -1  1  1]
 [-1 -1  1  1]]

That may not look very nice so lets visualize them a bit better.

# visualize all four filters
fig = plt.figure(figsize=(10, 5))
for i in range(4):
    ax = fig.add_subplot(1, 4, i+1, xticks=[], yticks=[])
    ax.imshow(filters[i], cmap='gray')
    ax.set_title('Filter %s' % str(i+1))
    width, height = filters[i].shape
    for x in range(width):
        for y in range(height):
            ax.annotate(str(filters[i][x][y]), xy=(y,x),
                        horizontalalignment='center',
                        verticalalignment='center',
                        color='white' if filters[i][x][y]<0 else 'black')

f:id:unifa_tech:20200129154136p:plain
Filters
Now that makes sense right. This shows which part of the image the filter will look for sharp contrast in the pixels.
Next we will define a simple CNN and our own weights.

# Conv Arch
class Net(nn.Module):
    def __init__(self, weight):
        super(Net, self).__init__()
        # initializes the weights of the convolutional layer to be the weights of the 4 defined filters
        k_height, k_width = weight.shape[2:]
        self.conv = nn.Conv2d(1, 4, kernel_size=(k_height, k_width), bias=False)
        self.conv.weight = torch.nn.Parameter(weight)
    def forward(self, x):
        # calculates the output of a convolutional layer
        # pre- and post-activation
        conv_x = self.conv(x)
        activated_x = torch.relu(conv_x)
        return conv_x, activated_x

Then we will define the weights (randomly initiazlized)

# instantiate the model and set the weights
weight = torch.from_numpy(filters).unsqueeze(1).type(torch.FloatTensor)
model = Net(weight)

# print out the layer in the network
print(model)

Now to call the model we can do this which will return both the convolutional outputs as well as the activation outputs

# convert the image into an input Tensor
gray_img_tensor = torch.from_numpy(gray).unsqueeze(0).unsqueeze(1)
# get the convolutional layer (pre and post activation)
conv_layer, activated_layer = model(gray_img_tensor)

The pre activation output will be this
f:id:unifa_tech:20200129154656p:plain
and the post activation output will be this
f:id:unifa_tech:20200129154721p:plain
Now this may not look like the common edge detection that you are used to, that is because we need another step to get the final output of edges.
We will have to add each edge together which will give what you would expect.

print(activated_layer.detach().numpy().shape)
# print out (1, 4, 2617, 4653)
edge = activated_layer.detach().numpy()
edge = np.squeeze(edge)
merged_1 = np.add(edge[0], edge[1])
merged_2 = np.add(edge[2], edge[3])
merged_edge = np.add(merged_1, merged_2)
print(merged_edge.shape)
# prints out (2617, 4653)
plt.imshow(merged_edge,cmap='gray')
plt.show()

Which will then give you the final edge detection image.

f:id:unifa_tech:20200129154917p:plain
Edge Detection

Now lets compare to OpenCV built in one

img = cv2.imread('data/f15.jpg',0)
edges = cv2.Canny(img,100,200)
plt.imshow(edges,cmap='gray')
plt.show()

Which will give you this image.

f:id:unifa_tech:20200129155034p:plain
OpenCV

Conclusion

Better results can be obtained by working with both of these two. But using the most basic of filters the CNN outperformed the OpenCV version. Ways you can improve both is by working with the filter of the CNN and adding layers to the CNN to improve the quality of features that are extracted. OpenCV you can adjust its parameters to fine-tune it for the specific image, but this will not work for a different image, while the CNN new filters will. Both of these can be put on as Raspberry Pi, but the Pytorch model will run just as fast as the OpenCV method but will give much better results in the end.

ユニファのシステムの移り変わり(前編)

おはこんにちばんは! ユニファのインフラ見てますすずきです。

私は新年最初のブログになります。 そして春になれば私も入社4年が経つなと思い、ユニファのシステムの遍歴でもまとめてみるかとおもい、ブログに書いてみます。

ただ、入社前の部分も書いてるので、そのあたりが適当なのはご容赦ください。

続きを読む

Swift for TensorFlowで頭部姿勢推定をやってみる

こんにちは、iOSエンジニアのしだです。
前回、Swift-Jupyter について書いたのですが、本当はSwift for TensorFlowを使って頭部姿勢推定(Head pose estimation)をやりたかったのでこちらをやってみたいと思います。

tech.unifa-e.com

頭部姿勢推定(Head pose estimation)

頭部姿勢推定は、カメラからみた頭の向きの推定を行うことです。 そのままですが、画像から頭の向きを pitch、 yaw、 roll の3つの値を予測することになります。

続きを読む