このエントリーをはてなブックマークに追加

2017年1月31日火曜日

Gemのバージョンをプロジェクトごとに分ける方法

こんにちは。h_ono_222です。

複数のアプリケーションを同時に開発している場合、同じGemでもそれぞれのアプリケーションごとにバージョンを分けたい場合があると思います。
今回はその方法を紹介します。


1. 空のプロジェクトを作成する

$ mkdir test_app && cd test_app
$ bundle init
Writing new Gemfile to /Users/user_name/test_app/Gemfile


2. Gemfileを修正する

# gem "rails"のコメントアウトを外します。


3. インストール先を指定してbundle install

$ bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/ 
Fetching version metadata from https://rubygems.org/ 
Fetching dependency metadata from https://rubygems.org/ 
Resolving dependencies....
# 〜中略〜
Bundle complete! 1 Gemfile dependency, 38 gems now installed.
Bundled gems are installed into ./vendor/bundle.


4. アプリケーションを作成する

$ bundle exec rails new .
       exist  
      create  README.md
      create  Rakefile
      create  config.ru
      create  .gitignore
    conflict  Gemfile
Overwrite /Users/DevWork/Documents/test_app/Gemfile? (enter "h" for help) [Ynaqdh] Y # Yを入力してEnter
force  Gemfile
# 〜中略〜
Bundle complete! 15 Gemfile dependencies, 62 gems now installed.
Bundled gems are installed into ./vendor/bundle.
         run  bundle exec spring binstub --all
* bin/rake: spring inserted
* bin/rails: spring inserted

以上です。

2017年1月30日月曜日

配牌からあがれる可能性を予測する!(その4 勾配を求める際に詰まったこと)

こんにちは、Taroです。
前回の記事の記事の続きになります。
配牌からあがれる可能性を予測する!(その3 学習の実装)
本日は学習を実装する上で、すぐに理解できなかった勾配算出に関わる部分をまとめたいと思います。

前回の訂正


損失値を算出して、グラフ化しておりましたが、1回ごとの平均値として算出しておりませんでした。
そのため、実際にどれくらいの誤差が生じているか分かりづらかったため、平均値で図をプロットするよう修正しました。
差分はこちらです。
https://github.com/naoki85/python_mahjong/commit

勾配法について


ある重み、バイアスパラメーターのときの、損失関数の勾配(傾き)を求め、傾きが小さくなるようパラメーターを変化させる手法とのことです。
機械学習はこの最適パラメーターを求めるのが1つの命題となっています。
ただ、パラメーターを決めると一口で言っても無限に近い数値の海から探さなければいけません。
ここで本の中で使っていた例えは、思わずへ〜、と頷いてしまいました。
文中ででてくるSGDは、確率的勾配降下法という手法の略です。

ここに風変わりな冒険家がいます。彼は広大な乾燥地帯を旅しながら、日々深い谷底を求めて旅を続けています。

~~中略~~

しかも、彼は、厳しい”制約”を2つ自分に課しています。ひとつは地図を見ないこと、もうひとつは目隠しをすることです。

~~中略~~

この困難な状況で重要となってくるのが、地面の「傾斜」です。

~~中略~~

そこで、今いる場所で一番傾斜がきつい方向に進もうというのが、SGDの戦略です。

「ゼロから作るDeep Learning」第6章より引用


勾配を算出する関数について


さて、実際に勾配を算出する段になりまして、少し理解が追いつきませんでした。
例えば、損失関数に対する微分は下記のようになります。(本の中の式)
# xはテストデータ、tは教師データです。
# lossは損失関数です。
def f(W):
    return net.loss(x, t)
ここで関数fはxとtから求める損失関数、f(W)でWに関する関数になります。
(Pythonではlambda式で一行で書けるようですが、あえてこちらで記載します。)
fをWに関して微分して勾配を求めます。

ここで、高校数学程度の知識しかない私はこう思いました。
あれ、fをWに関して微分しても、Wが要素になってないから0なんじゃないか、と。
とりあえずこの疑問は置いておいて、本を読み進めていくと、どう考えても勾配を0として計算しているようには見えませんでした。
Wをどこかで関わらせているのかと思い、勾配を求める関数をちゃんと読んでみました。
# 実際に呼んでいるコード
# net.Wはネットワーククラスが持つ重みの値(クラスプロパティ)
dW = numerical_gradient(f, net.W)

def numerical_gradient(self, f, x):
    h = 1e-4
    grad = np.zeros_like(x)
    
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        tmp_val = x[idx]
        # ここでプロパティの値を上書きしている!
        x[idx] = float(tmp_val) + h
        fxh1 = f(x)
        
        x[idx] = tmp_val - h
        fxh2 = f(x)
        grad[idx] = (fxh1 - fxh2) / (2*h)
        
         # ここで元に戻している!
        x[idx] = tmp_val
        it.iternext()
        
    return grad
つまり、重みパラメーターをクラスに持たせることで、微分式内で値を暫定的に書き換えて処理をさせています。
恥ずかしながら、ここで引っかかり、いまいち以降の処理を理解できておりませんでした。
もし、こちらの本で勉強していて、同じような場所で詰まっているという方がいらっしゃれば、参考にしていただければ、と思います。

2017年1月28日土曜日

iOS SwiftでS3への画像アップロード

 こんにちは、Hiroです。今回はSwiftでAWSのS3へ画像をアップロードする方法について、ブログを書きたいと思います。
 AWS Cognitoでの認証が本来は望ましいのですが、今回は簡単にIAMユーザを作成し、ACCESS KEYとSECRET ACCESS KEYを利用した方法で紹介したいと思います。アプリをリリースする場合は、AWS Cognitoを利用するか、IAMユーザの場合は、アクセス権限を十分に絞ってください。


AWS上での事前準備


AWS上での準備については、省略しますが下記の2つを準備してください。IAMユーザについては、作成したS3のバケットへアップロード(PutObject)できる権限を付与しておく必要があります。
  • S3にバケットを作成
  • IAMユーザの作成(上記のバケットへの「s3:PutObject」権限あり)

CocoaPodsでAWS SDKをインストールをする


Podfileに下記を記載して、インストールします。
  use_frameworks!

  pod 'AWSS3'
$ pod install


認証の設定をする


冒頭で記載したとおり、今回はIAMユーザでの認証を行います。accessKeyとsecretKeyにはAWSで作成したIAMユーザのものを設定してください。
下記の処理は、S3で画像などをアップロードする前に1度だけ実行するようにします。
import AWSCore
...
...
    func configureService() {
        let credentialsProvider = AWSStaticCredentialsProvider(accessKey: "your access key", secretKey: "your secret key")
        let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.apNortheast1, credentialsProvider: credentialsProvider)
        AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration
    }


UIImageを保存して、URLを取得する


S3へ投稿するファイルは、一時的に端末内に保存して、そのURLをS3のSDKに指定する必要があります。
下記のメソッドで、S3へのアップロードする画像が保存されているURLを取得できます。
    private func generateImageUrl(_ uploadImage: UIImage) -> URL {
        let imageURL = URL(fileURLWithPath: NSTemporaryDirectory().appendingFormat("upload.jpg"))
        if let jpegData = UIImageJPEGRepresentation(uploadImage, 80) {
            try! jpegData.write(to: imageURL, options: [.atomicWrite])
        }
        return imageURL
    }


S3へアップロードする


下記のメソッドでS3へアップロードができます。下記のメソッドを呼ぶ前には、上記で記載している認証の設定を事前に実行する必要があります。
また、「uploadRequest?.bucket」にはAWS上で作成したバケット名を指定し、「uploadRequest?.key」にはS3上に保存したいファイル名を指定します。 なお、ファイル名は「test/hello.jpg」とするとAWSコンソールなどから見た際にtestフォルダ内にhello.jpgファイルが保存されているように見えるので、ファイルをまとめて管理したい場合には、「test/」などのプレフィックスをつけるとよいでしょう。
import AWSS3
...
...
    public func uploadImage(_ uploadImage: UIImage) {
        let transferManager = AWSS3TransferManager.default()
        let uploadRequest = AWSS3TransferManagerUploadRequest()
        uploadRequest?.bucket = "your S3 bucket name"
        uploadRequest?.key = "your file name on S3"
        uploadRequest?.body = generateImageUrl(uploadImage)
        transferManager?.upload(uploadRequest).continue({ (task: AWSTask) -> Any? in
            if task.error != nil || task.exception != nil {
                // エラー
            }
            return nil
        })
    }


2017年1月27日金曜日

Swift3でDateからその月の月末のDateを取得

こんにちはonukiです。

今回はSwift3でDateの月末が何日か取得したかったので
備忘録がてら、私が行った方法を紹介したいと思います。

実装

var date = Date()
let calendar = NSCalendar(identifier: NSCalendar.Identifier.gregorian)!

// 年月日時分秒のNSComponents
var comp = calendar.components([.year, .month, .day, .hour, .minute, .second], from: date as Date)

// 月初の0時0分0秒に設定
comp.day = 1
comp.hour = 0
comp.minute = 0
comp.second = 0
// ここでcalendar.date(from: comp)!すれば月初のDateが取得できます

// その月が何日あるかを計算します
let range = calendar.range(of: .day, in: .month, for: date as Date)
let lastDay = range.length

// ここで月末の日に変えます
comp.day = lastDay

// Dateを作成
let retDate = calendar.date(from: comp)!

上記では現在日時からDateを作成し、その月の月末にしてるので
例えば2017年1月に実行した場合下記のフォーマットで整形しprintすると「20170131」になります。
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd"
let dateStr: String = formatter.string(from: retDate as Date)
print(dateStr)

2017年1月26日木曜日

はじめの一歩 -Rails ActiveRecord編- SELECT4


どうも、はじめです。
前回はJOINについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT3
今回も引き続きJOINに関する内容ですが、JOINでも3つ以上のテーブルの結合について書いていこうと思います。


はじめに


3つ以上のテーブルの結合なので、結合できるテーブルを3つ用意します。

usersテーブル
[id: 1, user_name: 'Aさん'],
[id: 2, user_name: 'Bさん'],
[Id: 3, user_name: 'Cさん']

itemsテーブル
[id: 1, item_name: 'Rubyの本'],
[id: 2, item_name: 'Railsの本'],
[id: 3, item_name: 'PHPの本']

user_itemsテーブル(userが持っているitemを管理するテーブル)
[id: 1, user_id: 1, item_id: 1],
[id: 2, user_id: 1, item_id: 2],
[id: 3, user_id: 2, item_id: 3]

関連を説明すると以下のようになります。
user : user_item => 1 : n
item : user_item => 1 : n

それでは前回使用したincludesを使用して書いていこうと思います。


取得


・Aさんが持っているアイテムを全て取得したい場合
user_items = User.includes(user_items: :item).find(1)

上記のように記述することで以下のようなSQLが実行されます。
SELECT `users`.* FROM `users` WHERE `users`.`id` = 1;
SELECT `user_items`.* FROM `user_items` WHERE `user_items`.`id` in (1,2);
SELECT `items`.* FROM `items` WHERE `items`.`id` in (1,2);

joinsの場合も同様の書き方となります。


表示


アイテム名を表示したい場合は以下のようにします。
user_items.user_items.each do |user_item|
  p user_item.item.item_name
end
# => 'Rubyの本'
# => 'Railsの本'


さらにテーブルが増えた場合


itemsにcategoryテーブルを関連付けして色々なパターンで取得をしてみたいと思います。
以下のような関連性でitemsに対し、categoriesテーブルを作成します。
items : category => n : 1

itemsテーブル
[id: 1, item_name: 'Rubyの本', category_id: 1],
[id: 2, item_name: 'Railsの本', category_id: 1],
[id: 3, item_name: 'PHPの本', category_id: 2]

categoriesテーブル
[id: 1, category_name: 'Ruby'],
[id: 2, category_name: 'PHP']

パターン1
・Aさんが持っているアイテムのカテゴリーまで取得したい場合
User.includes(user_items: {item: :category}).find(1)

パターン2
・"Rubyの本"のカテゴリーと持っているユーザーを取得したい場合
Item.includes(:category, {user_items: :user}).find(1)


まとめ


以下のような関連性だった場合
a:b:c => 1:n:1
c:d =>n:1

隣接しているテーブルを複数結合したい場合はのように「,」でつなげることができます。
B.includes(:a, :c)
二つ隣のテーブルの情報を取得する場合は「:」を向かい合わせに記述をします。
A.includes(b: :c)
さらに深いテーブルの情報を取得する場合は{}を使用します
A.includes(b: {c: :d})

前回も記述をしたように
3つ以上のテーブルを結合する場合でもテーブル名は
複数系、単数系を意識しなければいけませんので注意してください。

以上でSELECT系(JOIN系)を終了し、
次回からはUPDATEに入ろうと思います。