メインコンテンツまでスキップ

· 約5分

Controller

  • HTTP Requestを処理するやつ

  • @Controller()をクラス定義前に付ける

    @Controller('cats')
    export class CatsController {
  • 上記の例は/catsがパスになる

  • GETメソッドの定義

    @Get()
    findAll(): string {
    return 'This action returns all cats';
    }
  • @Get('breed')だとパスは/cats/breedになる

Provider

  • Service, Respository, Factory, Helperなどの総称

  • ProviderModuleに登録すると使える

    @Module({
    controllers: [CatsController],
    providers: [CatsService],
    })
    export class AppModule {}

Service

  • DBなどからデータをとってくるやつ

  • @Injectable()をクラス定義に付ける

    @Injectable()
    export class CatsService {
  • Controllerのコンストラクタの引数にすればインスタンスを注入できる

    @Controller('cats')
    export class CatsController {
    constructor(private catsService: CatsService) {}

Module

  • アプリを構造化するやつ

  • @Moduleをクラス定義につける

    @Module({
    controllers: [CatsController],
    providers: [CatsService],
    imports: [...],
    exports: [...],
    })
    export class CatsModule {}

MiddleWare

  • HTTPリクエストの処理の前に付けるやつ

  • 関数でもクラスでも作成できる

  • クラスの例

    @Injectable()
    export class LoggerMiddleware implements NestMiddleware {
    use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
    }
    }
  • Moduleconfigureメソッドで注入できる

    @Module({
    imports: [CatsModule],
    })
    export class AppModule implements NestModule {
    configure(consumer: MiddlewareConsumer) {
    consumer
    .apply(LoggerMiddleware) // Middlewareを登録
    .forRoutes('cats'); // `/cats`パスにMiddlewareを適用
    }
    }
  • forRoutesControllerを渡してもよい

    .forRoutes(CatsController);
  • Fuctional middlewareの例

    次の引数も持ったただの関数

    export function logger(req: Request, res: Response, next: NextFunction) {
    console.log(`Request...`);
    next();
    };
  • 以下のように適用する

    consumer
    .apply(logger)
    .forRoutes(CatsController);

Pipe

  • Route handlerの引数に適用して、引数の変換やバリデーションを行うやつ

  • ビルトインのParseIntPipeの使用例

    @Get(':id')
    async findOne(@Param('id', ParseIntPipe) id: number) {
    return this.catsService.findOne(id);
    }
  • インスタンス化を自分ですることもできる

    @Get(':id')
    async findOne(
    @Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
    id: number,
    ) {
    return this.catsService.findOne(id);
    }
  • Pipeの処理が失敗すると例外を投げる

  • Custom pipeの例

    @Injectable()
    export class ValidationPipe<T, R> implements PipeTransform<T, R> {
    transform(value: T, metadata: ArgumentMetadata): R { // 必須メソッド
    return convert(value);
    }
    }
  • valuePipeを適用する関数の引数

  • ArgumentMetadataは以下の情報を持っている

    export interface ArgumentMetadata {
    type: 'body' | 'query' | 'param' | 'custom';
    metatype?: Type<unknown>;
    data?: string;
    }

Guard

  • Route handlerの前に作用して、そのRoute handlerを実行するかしないかを決定するやつ

  • Middlewareに比べて、どのRoute handlerに適用されるのか詳細に設定できる

  • よく認証の確認に使われる

    @Injectable()
    export class AuthGuard implements CanActivate {
    // 必須のメソッド
    canActivate(
    context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    return validateRequest(request);
    }
    }
  • Guardの適用

    @Controller('cats')
    @UseGuards(RolesGuard)
    export class CatsController {}
  • @UseGuardsController内のメソッドにも適用できる

  • Guard内で対象のRoute handlerに付けられたdecoratorを参照することが可能

    Route handlerに付けるCustom decoratorの作成:

    export const Roles = Reflector.createDecorator<string[]>();

    RolesRoute handlerに適用する:

    @Post()
    @Roles(['admin'])
    async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
    }

    RolesGuardから参照する:

    @Injectable()
    export class RolesGuard implements CanActivate {
    constructor(private reflector: Reflector) {}

    canActivate(context: ExecutionContext): boolean {
    // ExecutionContextからRolesを取得できる
    const roles = this.reflector.get(Roles, context.getHandler());
    if (!roles) {
    return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return matchRoles(roles, user.roles);
    }
    }

Interceptor

  • Route handlerの前後に処理を挟むことができるやつ

  • NestInterceptorを継承する

  • intercept()メソッドを実装する

  • intercept()メソッドの引数はExecutionContextCallHandlerの2つ

  • CallHandlerRoute handlerのこと

  • intercept()メソッドの中でCallHandlerを実行しないと、Route handlerは実行されない

  • LoggingInterceptorの例

    @Injectable()
    export class LoggingInterceptor implements NestInterceptor<T, R> {
    intercept(context: ExecutionContext, next: CallHandler): Observable<R> {
    console.log('Before...');

    const now = Date.now();
    return next
    .handle() // Observale<T>
    .pipe(
    tap(() => console.log(`After... ${Date.now() - now}ms`)),
    );
    }
    }
  • Interceptorの適用

    @UseInterceptors(LoggingInterceptor)
    export class CatsController {}
  • メソッドレベルにも適用できる

参考

· 約6分

Tensor

import torch
torch.tensor([0, 1, 2, 3]) # long型
torch.Tensor([0, 1, 2, 3]) # float型
torch.arange(4) # tensor([0, 1, 2, 3])
torch.zeros(4) # tensor([0, 0, 0, 0])
torch.ones(1) # tensor([1, 1, 1, 1])
torch.tensor([[0, 1, 2], [3, 4, 5]]) # 2x3行列
torch.Tensor(2, 3) # ランダムに初期化された2x3行列
torch.arange(6).reshape(2, 3) # 1次元配列をを2x3行列に変換
torch.arange(4) + 2 # tensor([2, 3, 4, 5])
torch.arange(4) * 2 # tensor([0, 2, 4, 6])
torch.arange(4).reshape(2, 2) * 2 # tensor([[0, 2], [4, 6]])
a = torch.arange(4).reshape(2, 2)
b = torch.arange(4).reshape(2, 2)
a + b # tensor([[0, 2], [4, 6]])
a = torch.arange(4).reshape(2, 2)
b = torch.arange(4).reshape(2, 2)
a * b # tensor([[0, 1], [4, 9]])
a = torch.arange(4)
b = torch.arange(4)
torch.dot(a, b) # 内積: tensor([[0, 1, 4, 9]])
a = torch.arange(4).reshape(2, 2)
b = torch.arange(2).reshape(2, 1)
torch.matmul(a, b) # 行列積: tensor([[1], [3]])
torch.arange(24).reshape(-1, 2, 4) # `-1`は余りの次元。この場合, 24 / (2 * 4) = 3 次元
a = torch.arange(4)
a.dtype # torch.int64
torch.tensor([1, 2, 3], dtype=torch.float) # floatのtensorを生成
a = torch.tensor([1, 2, 3])
b = a.numpy() # numpyの配列に変換
torch.from_numpy(b) # numpyの配列をtensorに変換
a = torch.Tensor(2, 3)
b = torch.Tensor(2, 3)
torch.cat([a, b]) # 4x3行列を生成
torch.cat([a, b], dim=1) # 2x6行列を生成
a = torch.Tensor(2, 3)
b = torch.Tensor(2, 3)
c = torch.Tensor(2, 3)
torch.stack([a, b, c]) # 2x3行列を3つ持つバッチ
a = torch.Tensor(2, 3)
a.unsqueeze(0) # torch.stack([a])と同じ
a = torch.Tensor(3, 2, 2)
a.permute(2, 0, 1) # 軸の入れ替え: 元の次元のインデックスを指定する
x1 = torch.tensor([1.], requires_grad=True) # 微分を有効にする
x2 = torch.tensor([2.], requires_grad=True) # 微分を有効にする
x3 = torch.tensor([3.], requires_grad=True) # 微分を有効にする
z = (x1 - 2 * x2 - 1)**2 + (x2 * x3 - 1)**2 - 1
z.backward() # 微分値を計算
x1.grad # dz/dx1の値
x2.grad # dz/dx2の値
x3.grad # dz/dx3の値
# 何回も同じ変数で微分する時は毎回リセットする
x1 = x1.detach() # 微分値をリセット
x1 = x1.requires_grad_(True) # 微分を有効にする

おまじない

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import numpy as np
Pythonメモ

importfrom

import mylib
print(mylib.myfunc)
from mylib import myfunc
print(myfunc)

モデルの定義

class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
# 全結合層: 第1層(4 units) -> 第2層(6 units)
self.l1=nn.Linear(4, 6)

# 全結合層: 第2層(6 units) -> 第3層(3 units)
self.l2=nn.Linear(6, 3)

# 順伝播
def forward(self, x):
# 第2層(隠れ層)の値を計算
# 活性化関数: sigmoid
h1 = torch.sigmoid(self.l1(x))

# 出力層の値を計算
h2 = torch.l2(h1)
return h2
Pythonメモ

継承

class MyClass(SuperClass): # 親クラスを継承
def __init__(self, hoge):
# 親クラスのコンストラクタを呼び出す
# super(...)は親クラスのインスタンス
# super(...).`メソッド名`とすることで親クラスのメソッドを呼び出せる
super(MyClass, self).__init__(hoge) # Python2
super().__init__(hoge) # Python3

学習準備

# モデルの生成
model = MyModel()
# 確率的勾配降下法
# lr: 学習率
optimizer = optim.SGD(model.parameters(), lr=0.1)
# 損失関数: 交差エントロピー
criterion = nn.CrossEntropyLoss()
SDG

全ての訓練データに対する損失を使ってパラメータを1回更新する学習をバッチ学習と言う。それに対して、ランラムに選ばれた1つの訓練データに対する損失関数を使ってパラメータを1回更新する学習をSDG(確率的勾配降下法)と言う。

ミニバッチ

1つの訓練データごとにパラメータの更新を行う学習に対して、ある程度の訓練データの集合単位でパラメータを更新する学習もSDGと呼ばれる。このある程度の訓練データの集合をミニバッチと言う。

学習

n = 75 # 訓練データの数
bs = 25 # ミニバッチのサイズ
model.train()
for i in range(1000): # エポック数: 1000
idx = np.random.permutation(n) # 0からn-1まで数をランダムにn個取り出す
for j in range(0, n, bs): # 0, 25, 50
# bs個のデータを抽出
input_batch = input[idx[j:(j+bs) if (j+bs) < n else n]]
target_batch = target[idx[j:(j+bs) if (j+bs) < n else n]]

output = model(input_batch) # モデルの出力を計算
loss = criterion(output, target_batch) # 答えとの誤差を計算
print(i, j, loss.item()) # 誤差を出力
optimizer.zero_grad() # 微分値のリセット
loss.backword() # 微分
optimizer.step() # パラメータの更新(勾配分だけ移動)
逆誤差伝播法

損失関数の微分を効率よく実行する方法。

テスト

model.eval()
with torch.no_grad():
output = model(input)
ans = torch.argmax(output, 1)
print(((target == ans).sum().float() / len(ans)).item())

· 約20分

本記事の内容

本記事はReactでユーザのGoogleアカウントでGoogleにログインする方法をご紹介します。

Googleにログインすると、例えば以下のことが出来るようになります。

  • Google APIを使ってユーザーの情報を取得できるようになる。
  • 本人確認ができるため自前の認証の仕組みを実装しなくてよくなる。 (注1)

今回はGoogleにログインし、その認証情報を使ってユーザの基本的な情報をGoole APIで取得するまでをご紹介します。