Глобальная сеть искусственного интеллекта YOLO11 регистрирующая пиксельные объекты. Упадочно и порочно.

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор raoulduke666
Статья написана для
Конкурса статей #10


S7jzuoRb09g.jpg


«Здесь я вижу блондинку, брюнетку, рыженькую…»

Введение.
Приятно потраченное время самый ценный ресурс.
В этой статье расскажу как я заставил ИИ смотреть порно. Будет еще телега про парсер на golang, ферзь игры.
Прежде чем погрузиться в статью, рекомендую ознакомиться с терминологией.

Термины.
• Пентест порно - это метод оценки контента через ИИ.
• Pinkhat - атакующий поток, собирающий данные.
• YOLO11 - Модель нейросети для детекции.
• GAY11PORN (Global AI Yolo11 Porn Object Registration Network) - протокол для просмотра порно искуственным интелектом.
*Важное уточнение, в моем примере ИИ обучен воспринимать только женщин. Он заточен под поиск солож и лесбиянок. В следующих версиях будет подкручен парсинг анкет в дв/tinder + нейропробив, это для тех кто real player.
• Человеческая сила - кожаная внесистемная еденица мощности для определения производительности ИИ с протоколом GAY11PORN.
• Экзситенциальное поражение - последствия просмотра слишком большого количества порно во время сборки и разметки датасэта. ВНИМАНИЕ: НЕ БОЛЬШЕ 1 ЧАСА РАЗМЕТКИ В СУТКИ.

Зачем?
Личный опыт подсказывает, что мы определяем валидность порно субъективно и с каждой минутой скрола субъективность дает о себе знать все больше. Как спецназ, который врывается на участок, закидывает в твое окно флэшки, количество которых прямопропорционально количеству проскроленных видео. Ты уже проиграл, ты ослеп и схавал то что тебе скормили рекомендации или то что попалось под курсор из за нехватки времени на поиск.
Каждому знакомо чувство, когда не понравилась превьюшка/первые кадры вследствие чего отношение к контенту заведомо негативное, а потом еще около часа скролить порнхаб, безуспешно, оценивая пиксельные огрызки целого контента из за травматичного опыта в начале скрола. Своего рода ошибка, возникновение сознания - сбой на конвейере - засор в говнопроводе - смерть. Тоска, безысходность, ужас. Так ли это?

Порнопарсер помогает ответь каждому на этот вопрос. А также избежать этого хаоса, в короткие сроки обработав большое количество порно, чтобы сузить круг поиска подходящих пикселей. 3 человеческих силы, работающих на вашем датасэте продемонстрировано в статье.
Да и просто чтобы банить жирух, Посмотри на нее в последний раз. Больше ты ее не увидишь.
fGpSJhi0F7I.jpg



Требования.
• GPU nvidia 30-50 серия, +8 гб.
• ОЗУ +16гб.
• Топ нервы + железные яйца чтобы оставаться объективным. Это касательно разметки и датасета.

ИИ.
YOLO11. Модель нейросети для калссификации и детекции.
ИИ работает на python. Вообще он может работать на golang, что скорее всего было бы правильнее, но я не осилил и даже не пытался особо + удушающий соответствует тематике парсинга.
ИИ представляет из себя сервер на питоне, который принимает пакеты со скриншотами и данные о контенте, который прогоняется.
Пакет содержит 8 скриншотов, колличество пакетов зависит от колличества одновременно работающих вкладок в браузере. Колличество скриншотов в моем случае 1 скрншот в секунду на протяжении 8 секунд.
YOLO11 может обработать только 23 кадра в секунду. Пакет, который записывается на протяжении 8 секунд прогоняется на сервере за 1/3 секунды. Что позволяет работать с большим количеством вкладок. Все происходит в реальном времени.
Все это нужно чтобы весь невалидный контент добавить в банлист или искать какой то опредленный предмет. То есть ничто не мешает найти контент с бейсбольными шарами и бейсибольной битой. Для сборки датасэта не обязательно даже порно смотреть с такими же предметами. Просто картинки женщин с битами найти.

+ это удобная структура, можно получать данные не только от порно, это может быть что угодно. Если очевидно позволяют ресурсы. Или не дай бог убрать порнопарсер...

PRpdu6hMyo4.jpg



Для работы сервера с ИИ надо установить библиотеки:
Код: Скопировать в буфер обмена
Код:
pip install opencv-python
pip install ultralytics
pip install Flask
pip install numpy

опенсв для обработки скрншотов.

ультралитикс для работы самой нейронки.

+ скачиваем cuda для работы на видеокарте


Python: Скопировать в буфер обмена
Код:
import cv2

from ultralytics import YOLO

from collections import defaultdict

from flask import Flask, request, jsonify

import numpy as np

import asyncio

import threading

import queue

import logging



logging.basicConfig(level=logging.INFO)



# объявление модели YOLO11

model = YOLO("C:/Users/ebosh/Wadjet/best.pt")



app = Flask(__name__)



# словарь для класса

class_counts = defaultdict(int)



# очередь для изображений

image_queue = queue.Queue()



# остановки потока

stop_thread = False



def display_frame(annotated_frame):

    cv2.imshow("Annotated Frame", annotated_frame)

    cv2.waitKey(1)  # обработка окна



async def process_image(file_content):

    in_memory_file = np.frombuffer(file_content, np.uint8)

    frame = cv2.imdecode(in_memory_file, cv2.IMREAD_COLOR)



    if frame is not None:

        logging.info("Image decoded successfully.")

        results = model.predict(frame)



        if results:

            logging.info("Results obtained from model.")

            for result in results:

                for box in result.boxes:

                    class_id = int(box.cls)

                    class_name = result.names[class_id]

                    class_counts[class_name] += 1



            annotated_frame = results[0].plot()

            display_frame(annotated_frame)  # отображение аннотированного кадра



        else:

            logging.info("No results from model.")



async def process_images():

    while not stop_thread:

        try:

            file_content = image_queue.get(timeout=1)

            await process_image(file_content)

            await asyncio.sleep(1 / 20)

        except queue.Empty:

            continue

        except Exception as e:

            logging.error(f"Error processing image: {e}")



@app.route('/process', methods=['POST'])

def enqueue_image():

    if not request.files:

        return jsonify({'error': 'No images provided'}), 400



    for key in request.files:

        file = request.files[key]

        logging.info(f"Received image: {file.filename}")

 

        file_content = file.read()

        image_queue.put(file_content)



    return jsonify({'message': 'Images added to processing queue'}), 200



@app.route('/stop', methods=['POST'])

def stop_processing():

    global stop_thread

    stop_thread = True

    cv2.destroyAllWindows()  # Закрытие всех окон OpenCV

    return jsonify({'message': 'Processing stopped'}), 200



if __name__ == '__main__':

    loop = asyncio.get_event_loop()

    threading.Thread(target=lambda: loop.run_until_complete(process_images()), daemon=True).start()

    app.run(port=5000)

чтобы запустить скрипт нужно чтобы питон и голэнг были в одной директории. просто запускаете парсер и он сам подрубит питон с ИИ.
Так же должна быть нейронка yolo11n.pt
datasets
yaml файл
обученая нейронка (best.pt)

Как разворачивать cvat.
Нужен для создания разметки, к ней перейдем позже. Чтобы запустить cvat нужен WSL2, докер, гит и браузер.

Команды для скачивания cvat и запуска контейнеров. У вас уже должен быть установлен докер, WSL2 и гит.

Код: Скопировать в буфер обмена
git clone https://github.com/cvat-ai/cvat
Код: Скопировать в буфер обмена
cd cvat
Код: Скопировать в буфер обмена
docker compose up -d
Код: Скопировать в буфер обмена
dev docker compose up -d

После запуска в докере должны отобразиться запущенные контейнеры.

Становится доступен lolcalhost:8080 для работы с разметкой, но перед этим нужно зарегаться для работы в cvat
Для этого заходим через wsl как бы в ваш профиль. убунту или дебиан.

После того как ввели пароль, нужно прописать эту команду. Она объявляет вас как бы суперпользователем

Код: Скопировать в буфер обмена
sudo docker exec -it cvat_server bash -ic 'python3 ~/manage.py createsuperuser'

затем надо указать логин и пароль для cvat. Теперь после всего этого можно приступить к следующему кругу ада.

Подготовка к работе с датасэтом.
Я собрал около 250 скриншотов с разных видосов. Хорошо если вы найдете несколько разных баб с разной фигурой в одной позе, таких поз много, сами можете разобраться.

Сборка и работа с датасэтом.
НЕ БОЛЬШЕ 1 ЧАСА В СУТКИ. В общем по cvat есть много гайдов. Нужно просто создать проект, загрузить в него таски: для обучения (70%датасэта) для тренировки (30%датасэта). Просто в таске обводите че хотите детектить, роляет разнообразность датасэта, его количество и есть ли противоречия в разметке.

A9jAWO_Ic3E.jpg



Обучение.
Чтобы обучить нейросеть директория должна выглядеть так:

datasets
-train (результат разметки в cvat, текстовик
-val (результат разметки в cvat, текстовик
-dataset
images
train (70%
val (30%)
labels
train (папка с текстовиками, результат работы в cvat)
val (папка с текстовиками, результат работы в cvat)

yolo11n.pt
data.yaml

в yaml файле содержится информация о классах и пути к датасэту с лейблами.

Код для обучения нейросети. При запуске важно обратить внимание на чем у вас запустилась нейронка.
При запуске в одной из строчек будет уазано cpu или gpu. По дфолту используется видюха, поэтому вы должны увидеть название вашей видеокарты, если видите название проца, то лучше закрыть обучение, проверить видит ли cuda видеокарту

Код: Скопировать в буфер обмена
Код:
from ultralytics import YOLO

# Load a COCO-pretrained YOLO11n model
model = YOLO("yolo11n.pt")

# Train the model on the COCO8 example dataset for 100 epochs
results = model.train(data="coco8.yaml", epochs=100, imgsz=640)

В этом случае нейронка 90 эпох обучается, потом 10 тренеруется.
Можно играть с этими парметрами, иногда увеличение эпох для тренировки дает результат лучше, но как будто ИИ становится требовательнее.

После обучения будут графики. Их надо бы читать чтобы правильно переобучить нейронку.

IMG_7669.jpeg


train/box loss показывает на сколько нейронка хорошо справляется с разметкой на боксах, именно этот график отвечает за обводку, а не за валидность самой детекции. должен идти вниз

train/cls loss этот график отвечает за валидность самой классификации. график должен идти вниз

train/dfl loss тоже самое что первый график

metrics/precision(B) чем выше график тем выше точность в плане погрешности. Кароче это ее уверенность. Если датасэт составлен правильно без разногласий в плане размтеки то график будет выше. То есть если вы блондинку отметите один раз как брюнетку, то это гг. Нужно быть внимательным. В моем случае есть подобные ошибки. То есть моя нейронка работает почти нормально но не уверенно, уровень уверенности на каждом классе держится в районе 0.3-0.6. Это очень плохой результат, но для порно пойдет…

metrics/recall(B) указывает на количество найденных классов на валидации. должен расти вверх. У меня тут тоже все плохо, половина классов просто не была определена в целом. Это из за маленького датасэта

val/cls loss. относится к потерям на валидации. Вообще везде где написано loss это потери, что хуево, поэтому лямку loss тянем вниз.

Парсер.
Для парсера используется golang. Обусловленно многопоточностью в виде горутин.
Все начинается с того что скрипт открывает раздел с контентом. Он получает ключи из текущей страницы чтобы сформировать из них очередь для раздачи горутинам (pinkhats).
Далее скрипт открывает 1 вкладку, включает видос и создает горутину на текущей вкладке, которая будет делать скриншоты и отправлять на сервер с ИИ. Затем новая вкладка и так до одновременно 4 работающих вкладок. Горутины могут работать параллельно.
Вкладки создаются последовательно потому что мейн контекст должен находиться на странице во время ее загрузки, иначе не получится нормально взаимодействовать со страницей, видос просто не будет загружаться. Если одновременно открыть 3 вкладки, мейн контекст будет на последней вкладке во время их загрузок, а потом переключаться если это пиздец крч бред, да и как будто даже переключение между вкладками как то не оч работает.

Касательно скриншотов. Они отправляются пакетами. В одном пакете может быть только 8 скриншотов из одной вкладки, которые были сделаны за 8 секунд. Можно установить колличесвто скрншотово, время записи скриншотов, изменить параметры пакета.

Парсер может запускаться до двух минут. Я так понял у меня были какие то ошибки связанные с рекламой на сайте и это причина такой задержки мб.

В общем сейчас это просто архитектура для многопоточной обработки кадров из разных источников в реальном времени.

C-подобный: Скопировать в буфер обмена
Код:
package main

import (
    "bytes"
    "context"
    "fmt"
    "io"
    "log"
    "mime/multipart"
    "net/http"
    "os/exec"
    "sync"
    "time"

    "github.com/chromedp/chromedp"
)

//эксперементальная функция для перемотки видео, не успел реализовать до конца.
func seekVideo(ctx context.Context, seconds int) error {
    return chromedp.Run(ctx,
        chromedp.Evaluate(fmt.Sprintf(`document.querySelector('video').currentTime = %d;`, seconds), nil),
    )
}


func clickPlayButton(ctx context.Context) error {
    return chromedp.Run(ctx,
        chromedp.WaitVisible(`.mgp_icon.mgp_pauseIcon`, chromedp.ByQuery),
        chromedp.Click(`.mgp_icon.mgp_pauseIcon`, chromedp.ByQuery),
    )
}

func captureAndSendScreenshots(ctx context.Context, duration time.Duration, batchSize int, videokeys string, seekSeconds int) error {
    ticker := time.NewTicker(1 * time.Second) // скрншот каждую секунду.
    defer ticker.Stop()

    endTime := time.Now().Add(duration)
    var screenshots [][]byte

    for time.Now().Before(endTime) {
        select {
        case <-ticker.C:

            screenshotBuffer, err := FullPageScreenshot(ctx)
            if err != nil {
                return fmt.Errorf("ошибка при создании скриншота: %w", err)
            }

            screenshots = append(screenshots, screenshotBuffer)

            if len(screenshots) >= batchSize {
                if err := sendScreenshotsBatch(screenshots, videokeys); err != nil {
                    return fmt.Errorf("ошибка при отправке пакета изображений: %w", err)
                }

                screenshots = nil
            }
        }
    }

    if len(screenshots) > 0 {
        if err := sendScreenshotsBatch(screenshots, videokeys); err != nil {
            return fmt.Errorf("ошибка при отправке оставшихся изображений: %w", err)
        }
    }

    if err := seekVideo(ctx, seekSeconds); err != nil {
        return fmt.Errorf("ошибка при перемотке видео: %w", err)
    }

    return nil
}

func sendScreenshotsBatch(screenshots [][]byte, videokeys string) error {
    var b bytes.Buffer
    w := multipart.NewWriter(&b)

    for i, screenshot := range screenshots {

        part, err := w.CreateFormFile(fmt.Sprintf("image%d", i), fmt.Sprintf("%s_screenshot%d.png", fmt.Sprintf(videokeys, i)))
        if err != nil {
            return err
        }

        _, err = part.Write(screenshot)
        if err != nil {
            return err
        }
    }
    w.Close()

    resp, err := http.Post("http://localhost:5000/process", w.FormDataContentType(), &b)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    fmt.Println("Response from Python:", string(body))
    return nil
}

func FullPageScreenshot(ctx context.Context) ([]byte, error) {
    var screenshotBuffer []byte
    err := chromedp.Run(ctx,
        chromedp.FullScreenshot(&screenshotBuffer, 100))
    if err != nil {
        return nil, err
    }
    return screenshotBuffer, nil
}

func sendScreenshotToPython(screenshots [][]byte) error {
    var b bytes.Buffer
    w := multipart.NewWriter(&b)

    // Создаем форму для каждого скриншота
    for i, screenshot := range screenshots {
        part, err := w.CreateFormFile(fmt.Sprintf("image%d", i), fmt.Sprintf("screenshot%d.png", i))
        if err != nil {
            return err
        }

        _, err = part.Write(screenshot)
        if err != nil {
            return err
        }
    }
    w.Close()

    resp, err := http.Post("http://localhost:5000/process", w.FormDataContentType(), &b)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    fmt.Println("Response from Python:", string(body))
    return nil
}

func main() {
    profilePath := "C:/Users/ebosh/AppData/Local/Google/Chrome/User Data"

    opts := append(chromedp.DefaultExecAllocatorOptions[:],
        chromedp.Flag("headless", true),
        chromedp.Flag("window-size", "1920,1000"),
        chromedp.Flag("user-data-dir", profilePath),
    )

    allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
    defer cancel()

    ctx, cancel := chromedp.NewContext(allocCtx)
    defer cancel()

    sectionURL := "https://rt.pornhub.com/video?c=492&o=cm"

    var videoKeys []string
    err := chromedp.Run(ctx,
        chromedp.Navigate(sectionURL),
        chromedp.WaitReady(`li.pcVideoListItem[data-action="browse"]`, chromedp.ByQuery), // WaitReady или WaitVisible
        chromedp.ActionFunc(func(ctx context.Context) error {
            ctx, cancel := context.WithTimeout(ctx, 5*time.Second) // Установите нужный таймаут
            defer cancel()

            return chromedp.Evaluate(`Array.from(document.querySelectorAll('li.pcVideoListItem[data-action="browse"]')).slice(0, 3).map(item => item.getAttribute('data-video-vkey'))`, &videoKeys).Do(ctx)
        }),
    )
    if err != nil {
        log.Fatal(err)
    }

    if len(videoKeys) == 0 {
        fmt.Println("Не найдено видео.")
        return
    }

    fmt.Println("Найденные видео:", videoKeys)

    cmd := exec.Command("C:/Users/ebosh/anaconda3/envs/yolo8/python.exe", "C:/Users/ebosh/Wadjet/ai.py")
    stdin, err := cmd.StdinPipe()
    if err != nil {
        log.Fatal(err)
    }

    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    stderr, err := cmd.StderrPipe()
    if err != nil {
        log.Fatal(err)
    }

    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }

    //горутинаконсоль
    go func() {
        output, err := io.ReadAll(stdout)
        if err != nil {
            log.Println("Ошибка при чтении stdout:", err)
            return
        }
        fmt.Println("Output from Python:", string(output))
    }()

    //горутинаошибки
    go func() {
        errorOutput, err := io.ReadAll(stderr)
        if err != nil {
            log.Println("Ошибка при чтении stderr:", err)
            return
        }
        if len(errorOutput) > 0 {
            log.Println("Error output from Python:", string(errorOutput))
        }
    }()

    //для ожидания завершения всех горутин
    var wg sync.WaitGroup

    for i, vkey := range videoKeys {
        fullscreenURL := fmt.Sprintf("https://rt.pornhub.com/embed/%s", vkey)
        fmt.Println("Создаем сессию для видео:", fullscreenURL)

        wg.Add(1) // Увеличить счетчик
        go func(i int, vkey string, fullscreenURL string) {
            defer wg.Done() // Уменьшить счетчик при завершении. Типа заранее объявляется чтобы не забыть.

            time.Sleep(time.Duration(i) * 8 * time.Second) // 0 сек для первого, 5 сек для второго, 10 сек для третьего

            newCtx, cancel := chromedp.NewContext(ctx)
            defer cancel()

            ctxWithTimeout, cancel := context.WithTimeout(newCtx, 120*time.Second)
            defer cancel()

            fmt.Println("Навигация к:", fullscreenURL)
            if err := chromedp.Run(ctxWithTimeout,
                chromedp.Navigate(fullscreenURL),
                chromedp.WaitVisible("body", chromedp.ByQuery),
            ); err != nil {
                log.Println("Ошибка при открытии видео:", err)
                return
            }
            fmt.Println("Страница загружена:", fullscreenURL)

            if err := clickPlayButton(ctxWithTimeout); err != nil {
                log.Println("Ошибка при нажатии на кнопку воспроизведения:", err)
                return
            }
            log.Println("Кнопка воспроизведения успешно нажата.")

            time.Sleep(5 * time.Second)

            if err := captureAndSendScreenshots(ctxWithTimeout, 60*time.Second, 8, vkey, 10); err != nil {
                log.Println("Ошибка при создании и отправке скриншотов:", err)
            }

            time.Sleep(5 * time.Second)

        }(i, vkey, fullscreenURL)
    }

    wg.Wait()

    if err := stdin.Close(); err != nil {
        log.Println("Ошибка при закрытии stdin:", err)
    }

    if err := cmd.Wait(); err != nil {
        log.Println("Ошибка при ожидании завершения Python-скрипта:", err)
    }
    fmt.Println("Завершение работы.")
}
_HurphurU5Y.jpg


8aKJuow_BaM.jpg


Lozw6HKkWh0.jpg


Здесь я вижу пакеты, в одном из пакетов была обнаружена ахуенная + худенькие пальцы + щавель. Насчет щавеля инфа не точная, мало детектов. fishing это чулки в сетку, которые были обнаружены на соседней вкладке.

Итоги ?
Что случится когда я прогоню все порно и заведомо буду знать что 90% остального контента мне не понравятся ? Я сосредоточусь на создании ИИ для поиска ресурсов ? Или мне надо будет пересмотреть свои взгляды чтобы остаться в игре ? Найти девушку ... ? Создать ИИ для поиска жертвы в тиндере? Каждый решает для себя сам.
IMG-7649.gif
 
Сверху Снизу