본문 바로가기
Project/어데고 (urdego)

[TensorFlow - NSFW] 부적절한 컨텐츠 감지

by J-rain 2025. 2. 18.

 

이번에는 Urdego 컨텐츠 서비스의 부적절한 컨텐츠 감지에 대한 포스팅을 작성하고자 합니다

 

 

도입 계기

  1. Urdego 프로젝트는 사용자가 생성하는 컨텐츠(UGC)를 게임에 사용하는 특성
  2. 익명성이 보장되는 플랫폼에서 '유해 콘텐츠가 업로드될 가능성'

 

해결방법

  1. Amazon Rekognition (AWS에서 제공하는 부적절한 이미지 및 비디오 감지 API)
  2. Cloud Vision API - SafeSearch (GCP에서 제공하는 유해성 컨텐츠 감지)
  3. Green-eye (Naver에서 제공하는 음란물 차단 AI)
  4. 등등...

찾아보면서 느낀점은 API를 사용하면 손쉽게 구축할 수 있지만 역시 사용에 따른 비용이 발생한다는 점이다..

블로그 포스팅하면서 매번 언급했지만 Urdego는 이미 비용문제 -> 홈서버로 구축했기에 부가적인 비용이 드는 행위(?)를 하고 싶지 않았다.

 

그렇게 API에서 오픈소스로 눈을 돌리고 종일 찾아본 결과..

이미지 처리에 많이 사용되는 TensorFlow가 부적절한 컨텐츠 감지 모델도 있다는 사실을 알아버렸다 👍🏻👍🏻

 

 

TensorFlow - NSFW(Not Safe For Work) ??

NSFW 머신러닝 모델은 이미지를 분석해서 아래 5가지 카테고리 중 하나로 분류하는 역할을 한다.

  1. drawings – 안전한 그림
  2. hentai - 성인 애니메이션
  3. neutral – 일반적인 안전한 이미지
  4. sexy – 선정적이지만 직접적인 포르노는 아닌 이미지
  5. porn – 실제 포르노 이미지 및 성행위

 

참고 깃헙 링크

https://github.com/tensorflow/java

https://github.com/GantMan/nsfw_model/tree/master?tab=readme-ov-file

 

GitHub - GantMan/nsfw_model: Keras model of NSFW detector

Keras model of NSFW detector. Contribute to GantMan/nsfw_model development by creating an account on GitHub.

github.com

 

 

우선 모델이 잘 작동되는지 'Colab' 에서 테스트사진을 업로드하여 인덱스별 비율을 추출해보자

import tensorflow as tf
import numpy as np
from PIL import Image

# 모델 로드
with tf.io.gfile.GFile("nsfw.pb", "rb") as f:
    graph_def = tf.compat.v1.GraphDef()
    graph_def.ParseFromString(f.read())


# 그래프 생성
with tf.Graph().as_default() as graph:
    tf.compat.v1.import_graph_def(graph_def, name="")

# 입력과 출력 노드 이름
input_node = "input_1"
output_node = "dense_3/Softmax"

# 디버깅: 노드 확인
print("Input Node:", input_node)
print("Output Node:", output_node)

# 이미지 전처리
def preprocess_image(image_path):
    img = Image.open(image_path).convert("RGB").resize((224, 224))
    img = np.array(img).astype(np.float32) / 255.0  # float32로 변환
    img = np.expand_dims(img, axis=0)
    print("Preprocessed Image Shape:", img.shape)
    return img

# 테스트 이미지 경로
image_path = "/content/테스트사진1.jpeg"
input_data = preprocess_image(image_path)

# 세션 실행
with tf.compat.v1.Session(graph=graph) as sess:
    try:
        # 입력과 출력 텐서
        input_tensor = graph.get_tensor_by_name(input_node + ":0")
        output_tensor = graph.get_tensor_by_name(output_node + ":0")

        # 모델 실행
        output = sess.run(output_tensor, feed_dict={input_tensor: input_data})


        for i, prob in enumerate(output[0]):  # 배치 내 첫 번째 결과 사용
            print(f"Class {i}: Probability = {prob}")
    except Exception as e:
        print(f"Error during session run: {e}")

 

풍경사진이

[Index 3] neutral – 일반적인 안전한 이미지  0.99 로 잘 추출된 모습이다.

 

내가만든 스콘

마찬가지로

[Index 3] neutral – 일반적인 안전한 이미지  0.99 로 잘 추출된 모습이다.

 

스키장에서 만난 애기

 

사람이 있어도 마찬가지로

[Index 3] neutral – 일반적인 안전한 이미지  0.96 으로 잘 추출된 모습이다.

 

 

19금 사진도 확인해보자,,

 

[Index 4] porn – 실제 포르노 이미지 및 성행위 0.86으로 잘 추출된 모습이다.

 

이렇게 50여가지의 사진들을 테스트한 결과

부적절한 컨텐츠 평균 Index 3, Index 4에서  0.6 이상이 추출되었다.

 

 

이제 내가 할일은 클라이언트에서 컨텐츠 생성 api 요청시 컨텐츠를 분리해서 서버에 저장된 nsfw 모델을 거친 후 결과를 리턴해주면 된다!

 

 

 

스웨거 테스트 결과
컨텐츠 서버 log

 

 

굳 👍🏻👍🏻

댓글