$30 off During Our Annual Pro Sale. View Details »

20171209 Sakura ML Night

ARIYAMA Keiji
December 09, 2017

20171209 Sakura ML Night

2017年12月9日に大阪で開催された「さくらの機械学習ナイト」の発表資料です。

「TensorFlowによるNSFW(職場で不適切な)画像検出」について。

ARIYAMA Keiji

December 09, 2017
Tweet

More Decks by ARIYAMA Keiji

Other Decks in Technology

Transcript

  1. C-LIS CO., LTD.

    View Slide

  2. C-LIS CO., LTD.

    ༗ࢁܓೋʢ,FJKJ"3*:"."ʣ
    $-*4$0 -5%
    "OESPJEΞϓϦ։ൃνϣοτσΩϧ
    Photo by Koji MORIGUCHI (MORIGCHOWDER)
    ػցֶश͸ͪΐͬͱ΍ͬͨ͜ͱ͋Γ·͢
    Twitter΍ͬͯ·ͤΜ

    View Slide

  3. ͘͞ΒͷػցֶशφΠτ


    5FOTPS'MPXͰ

    /4'8ը૾ݕग़

    View Slide

  4. 5FOTPS'MPXʢ೥݄ൃදʣ

    ػց஌ೳ޲͚ܭࢉϑϨʔϜϫʔΫ
    ࠷৽όʔδϣϯʢ೥݄ʣ

    View Slide


  5. ษڧձ΍Ζ͏ͥ

    View Slide


  6. (PPHMF%FWFMPQFS(SPVQ

    View Slide


  7. IUUQTHEHLPCFEPPSLFFQFSKQFWFOUT

    View Slide


  8. Πϯλʔωοτ͔Β
    ޷Έͷը૾ΛࣗಈͰऩू͍ͨ͠

    View Slide

  9. © ࠜઇΕ͍
    ؟
    ڸ
    ͬ

    View Slide

  10. ؟ڸ່ͬ൑ఆ

    1 0

    View Slide

  11. σʔληοτʢ೥݄࣌఺ʣ
    ؟ڸ່ͬɹຕ
    ඇ؟ڸ່ͬຕ

    ؟ڸ່ͬ ඇ؟ڸ່ͬ
    ޡݕग़
    ؟ڸ່ͬ
    ඇ؟ڸ່ͬ

    View Slide

  12. {
    "generator": "Region Cropper",
    "file_name": "haruki_g17.png",
    "regions": [
    {
    "probability": 1.0,
    "label": 2,
    "rect": {
    "left": 97.0,
    "top": 251.0,
    "right": 285.0,
    "bottom": 383.0
    }
    },
    {
    "probability": 1.0,
    "label": 2,
    "rect": {
    "left": 536.0,
    "top": 175.0,
    "right": 730.0,
    "bottom": 321.0
    }
    }
    ]
    }
    Region Cropper: https://github.com/keiji/region_cropper

    View Slide

  13. ߏ੒

    Downloader

    σʔληοτ
    Region +
    Label ઃఆ
    rsync

    View Slide

  14. ཧ૝ͷߏ੒

    Downloader Face Detection Megane Detection
    ֬ೝɾमਖ਼
    ೝࣝ݁Ռ
    ֶशʢ܇࿅ʣ
    λΠϜϥΠϯ ϝσΟΞ
    σʔληοτ
    ֶशʢ܇࿅ʣ
    TensorFlow

    rsync

    View Slide


  15. ௅ઓͷաఔΛಉਓࢽʹ

    View Slide

  16. ͞·͟·ͳ՝୊
    σʔληοτ͕(#Λ௒͑ͨ͋ͨΓ͔ΒϩʔΧϧ΁ͷಉظ͕ࠔ೉ʹɻ
    ྖҬʢ3FHJPOʣͷઃఆͱϥϕϧͷ෇༩͸૝૾Ҏ্ʹෛՙ͕ߴ͍ɻ

    View Slide


  17. ը૾͕ສຕΛಥഁ
    σʔλ੔ཧ͕ࢸٸͷ՝୊ʹ

    View Slide


  18. ໨ඪΛ࠶֬ೝ

    View Slide


  19. Πϯλʔωοτ͔Β
    ޷Έͷ؟ڸ່ͬը૾ΛࣗಈͰऩू͍ͨ͠

    View Slide

  20. Ҏલͷߏ੒

    Downloader

    σʔληοτ
    Region +
    Label ઃఆ
    rsync

    View Slide


  21. ྖҬʴϥϕϧ

    View Slide

  22. ৽͍͠ߏ੒

    Downloader

    σʔληοτ
    Tagઃఆ

    View Slide


  23. λά
    megane
    girl

    View Slide

  24. ؟ڸ່ͬ൑ผϞσϧ

    Ϟσϧ
    1.00
    0.00

    View Slide


  25. %BUBTFU.BOBHFSGPS"OESPJE

    View Slide


  26. σϞ

    View Slide

  27. https://twitter.com/35s_00/status/930366666973757441

    View Slide


  28. https://twitter.com/_meganeco

    View Slide


  29. /4'8ʢ/PU4BGF'PS8PSLʣ

    View Slide

  30. /4'8ը૾

    View Slide

  31. ͞·͟·ͳϦεΫ
    ࡞ۀͷϊΠζ
    ਫ਼ਆతͳෛՙ
    ๏తϦεΫ

    View Slide


  32. /4'8ը૾ͷݕग़

    View Slide

  33. ֶश༻σʔληοτʢ/4'8ʣ
    ਖ਼ྫɿ
    ෛྫɿ

    ← NSFWը૾

    View Slide


  34. ܇࿅ɾֶश

    View Slide

  35. ڭࢣ༗Γֶश


    ×
    Ϟσϧ
    1.00
    0.00

    View Slide

  36. Ϟσϧͷߏ଄

    conv
    3x3x64
    stride 1
    conv
    3x3x64

    stride 1
    ReLU ReLU
    conv
    3x3x128

    stride 1
    conv
    3x3x128

    stride 1
    ReLU
    conv
    3x3x256

    stride 1
    conv
    3x3x256

    stride 1
    ReLU
    output
    1
    256x256x1
    max_pool
    2x2
    stride 2
    max_pool
    2x2
    stride 2
    ReLU ReLU Sigmoid
    max_pool
    2x2
    stride 2
    conv
    3x3x64

    stride 1
    ReLU
    fc
    768
    ReLU
    bn
    bn
    bn

    View Slide


  37. Sigmoid

    View Slide

  38. # モデル定義
    NUM_CLASSES = 1
    NAME = 'model3'
    IMAGE_SIZE = 256
    CHANNELS = 3
    def prepare_layers(image, training=False):
    with tf.variable_scope('inference'):
    conv1 = tf.layers.conv2d(image, 64, [3, 3], [1, 1],
    padding='SAME',
    activation=tf.nn.relu,
    use_bias=False,
    trainable=training,
    name='conv1_1')
    conv1 = tf.layers.conv2d(conv1, 64, [3, 3], [1, 1],
    padding='VALID',
    activation=tf.nn.relu,
    use_bias=False,
    trainable=training,
    name='conv1_2')
    conv1 = tf.layers.batch_normalization(conv1, trainable=training, name='bn_1')

    View Slide

  39. conv2 = tf.layers.conv2d(pool1, 128, [3, 3], [1, 1],
    padding='VALID',
    activation=tf.nn.relu,
    use_bias=False,
    trainable=training,
    name='conv2_1')
    conv2 = tf.layers.conv2d(conv2, 128, [3, 3], [1, 1],
    padding='VALID',
    activation=tf.nn.relu,
    use_bias=False,
    trainable=training,
    name='conv2_2')
    conv2 = tf.layers.batch_normalization(conv2, trainable=training, name='bn_2')
    pool2 = tf.layers.max_pooling2d(conv2, [2, 2], [2, 2])

    View Slide

  40. conv3 = tf.layers.conv2d(pool2, 256, [3, 3], [1, 1],
    padding='VALID',
    activation=tf.nn.relu,
    use_bias=False,
    trainable=training,
    name='conv4_1')
    conv3 = tf.layers.conv2d(conv3, 256, [3, 3], [1, 1],
    padding='VALID',
    activation=tf.nn.relu,
    use_bias=False,
    trainable=training,
    name='conv4_2')
    conv3 = tf.layers.batch_normalization(conv3, trainable=training, name='bn_4')
    pool3 = tf.layers.max_pooling2d(conv3, [2, 2], [2, 2])
    conv = tf.layers.conv2d(pool3, 64, [1, 1], [1, 1],
    padding='VALID',
    activation=tf.nn.relu,
    use_bias=True,
    trainable=training,
    name='conv')
    return conv

    View Slide

  41. def output_layers(prev, batch_size, keep_prob=0.8, training=False):
    flatten = tf.reshape(prev, [batch_size, -1])
    fc1 = tf.layers.dense(flatten, 768,
    trainable=training,
    activation=tf.nn.relu,
    name='fc1')
    fc1 = tf.layers.dropout(fc1, rate=keep_prob, training=training)
    output = tf.layers.dense(fc1, NUM_CLASSES,
    trainable=training,
    activation=None,
    name='output')
    return output

    View Slide

  42. def _loss(logits, labels, batch_size, positive_ratio):
    cross_entropy = tf.nn.sigmoid_cross_entropy_with_logits(
    labels=labels, logits=logits)
    loss = tf.reduce_mean(cross_entropy)
    return loss
    def _init_optimizer(learning_rate):
    return tf.train.AdamOptimizer(learning_rate=learning_rate)

    ޡࠩؔ਺ͱ࠷దԽΞϧΰϦζϜ

    View Slide


  43. ֶशΛ্ख͘ਐΊΔ޻෉

    View Slide

  44. ਖ਼ྫɾෛྫͷൺ཰
    ਖ਼ྫɿ
    ෛྫɿ

    ← NSFWը૾
    NSFW

    View Slide

  45. def _hard_negative_mining(loss, labels, batch_size):
    positive_count = tf.reduce_sum(labels)
    positive_count = tf.reduce_max((positive_count, 1))
    negative_count = positive_count * HARD_SAMPLE_MINING_RATIO
    negative_count = tf.reduce_max((negative_count, 1))
    negative_count = tf.reduce_min((negative_count, batch_size))
    positive_losses = loss * labels
    negative_losses = loss - positive_losses
    top_negative_losses, _ = tf.nn.top_k(negative_losses,
    k=tf.cast(negative_count, tf.int32))
    loss = (tf.reduce_sum(positive_losses / positive_count)
    + tf.reduce_sum(top_negative_losses / negative_count))
    return loss

    )BSE/FHBUJWF.JOJOH

    View Slide

  46. ֶश؀ڥʢ͘͞ΒͷߴՐྗίϯϐϡʔςΟϯάʣ
    $169FPO$PSFʷ
    .FNPSZ(#
    44%(#
    (F'PSDF(595*5"/9ʢ1BTDBMΞʔΩςΫνϟʣ(#ʷ
    (F'PSDF(595Jʢ1BTDBMΞʔΩςΫνϟʣ(#ʷ

    View Slide

  47. ֶश৚݅
    ޡࠩؔ਺ަࠩΤϯτϩϐʔ
    ࠷దԽΞϧΰϦζϜ"EBN
    ֶश཰
    όοναΠζ

    View Slide


  48. View Slide


  49. View Slide

  50. طଘͷσʔληοτʹਪ࿦ʢJOGFSFODFʣΛ࣮ߦ

    Downloader
    σʔληοτ
    Tagઃఆ
    inference
    trainer
    ֶशࡁΈϞσϧ ֶश༻σʔληοτ

    View Slide

  51. ਪ࿦݁Ռ
    /4'8
    Ұൠը૾

    NSFW

    8.6%

    View Slide

  52. ֶश༻σʔληοτʢ/4'8ʣ
    ਖ਼ྫɿ ɹˠɹ
    ෛྫɿ ɹˠɹ

    View Slide

  53. ܇࿅ɾֶशʹ͔͔Δܭࢉ࣌ؒ

    View Slide


  54. View Slide


  55. σϞ
    (16ɾ$16ͷൺֱ

    View Slide

  56. $16ɾ(16ͷ଎౓ൺֱʢCBUDI4J[Fʣ
    5*5"/9
    TFDTUFQ
    9FPO$PSFTFDTUFQ

    ࠓճͷϞσϧͷֶशʹ͍ͭͯ͸
    5*5"/9ͷํ͕ഒ଎͍ʂ

    View Slide

  57. $16ɾ(16ͷ଎౓ൺֱʢCBUDI4J[Fʣ
    5*5"/9 (595J
    TFDTUFQ
    9FPO$PSFTFDTUFQ

    ࠓճͷϞσϧͷֶशʹ͍ͭͯ͸
    (16ʷͷํ͕ഒ଎͍ʂ

    View Slide


  58. ࠓޙͷ՝୊

    View Slide

  59. σʔληοταʔόʔͷ৴པੑ޲্

    View Slide

  60. JOGFSFODFʢਪ࿦ʣͷͨΊͷܭࢉࢿݯͷ֬อ

    Downloader
    σʔληοτ
    Tagઃఆ
    inference
    trainer
    ֶशࡁΈϞσϧ ֶश༻σʔληοτ

    View Slide

  61. TAGS = [
    'original_art',
    'nsfw',
    'like',
    'photo',
    'illust',
    'comic',
    'face',
    'girl',
    'megane',

    ϥϕϧʢλάʣ
    'school_uniform',
    'blazer_uniform',
    'sailor_uniform',
    'gl',
    'kemono',
    'boy',
    'bl',
    'cat',
    'dog',
    'food',
    'dislike',
    ]

    View Slide

  62. .PWJEJVT

    View Slide

  63. ਪ࿦Λ.PWJEJVT΁Ҡߦ

    Downloader
    σʔληοτ
    Tagઃఆ
    trainer
    ֶशࡁΈϞσϧ
    ֶश༻σʔληοτ
    inference

    View Slide

  64. Ϋϥε൑ఆϞσϧ

    conv
    3x3x64
    stride 1
    conv
    3x3x64

    stride 1
    ReLU ReLU
    conv
    3x3x128

    stride 1
    conv
    3x3x128

    stride 1
    ReLU
    conv
    3x3x256

    stride 1
    conv
    3x3x256

    stride 1
    ReLU
    output
    20
    256x256x1
    max_pool
    2x2
    stride 2
    max_pool
    2x2
    stride 2
    ReLU ReLU Sigmoid
    max_pool
    2x2
    stride 2
    conv
    3x3x64

    stride 1
    ReLU
    fc
    768
    ReLU
    bn
    bn
    bn

    View Slide

  65. C-LIS CO., LTD.
    ຊࢿྉ͸ɺ༗ݶձࣾγʔϦεͷஶ࡞෺Ͱ͢ɻຊࢿྉͷશ෦ɺ·ͨ͸Ұ෦ʹ͍ͭͯɺஶ࡞ऀ͔ΒจॻʹΑΔڐ୚Λಘͣʹෳ੡͢Δ͜ͱ͸ې͡ΒΕ͍ͯ·͢ɻ
    5IF"OESPJE4UVEJPJDPOJTSFQSPEVDFEPSNPEJpFEGSPNXPSLDSFBUFEBOETIBSFECZ(PPHMFBOEVTFEBDDPSEJOHUPUFSNTEFTDSJCFEJOUIF$SFBUJWF$PNNPOT"UUSJCVUJPO-JDFOTF
    ֤੡඼໊ɾϒϥϯυ໊ɺձ໊ࣾͳͲ͸ɺҰൠʹ֤ࣾͷ঎ඪ·ͨ͸ొ࿥঎ඪͰ͢ɻຊࢿྉதͰ͸ɺ˜ɺšɺäΛׂѪ͍ͯ͠·͢ɻ
    5IF"OESPJESPCPUJTSFQSPEVDFEPSNPEJpFEGSPNXPSLDSFBUFEBOETIBSFECZ(PPHMFBOEVTFEBDDPSEJOHUPUFSNTEFTDSJCFEJOUIF$SFBUJWF$PNNPOT"UUSJCVUJPO-JDFOTF
    https://speakerdeck.com/keiji/20171209-sakura-ml-night

    View Slide