天天看點

用 tensorflow.js 做了一個動漫分類的功能(一)

前言:

浏覽某乎網站時發現了一個分享各種圖檔的部落客,于是我順手就儲存了一些。但是一張一張的儲存實在太麻煩了,于是我就想要某蟲的手段來處理。這樣儲存的确是很快,但是他不識圖檔内容,最近又看了 mobileNet 的預訓練模型,想着能讓程式自己對圖檔分類,以下就通過例子從内容采集到分類的過程。

内容和資源的采集,反手就是某蟲了。在網絡上,經過近幾年的營銷渲染,可能首選是用 Python 做腳本。而這次是用 PHP 的 QueryList 來做采集,下面也就是采集的編碼過程和踩坑解決方法,最後再對采集圖檔進行标注和訓練。

用 tensorflow.js 做了一個動漫分類的功能(一)

環境:

PHP7.4

QueryList4.0

QueryList-CurlMulti

用 tensorflow.js 做了一個動漫分類的功能(一)

編碼:

以下例子是基于 TP5.1,是以隻需要安裝上面兩個依賴包。采集啟動通過自定義指令實作,接下來分别以普通采集和多線程采集兩種方式展示。

1. 普通采集

<?php/**
 * @Notes: 公衆号:ZERO開發
 * @Interface getCondition
 * @Return mixed
 * @Author: bqs
 * @Time: 2021/4/19 15:28
 */namespaceapp\common\command;

usethink\console\Command;
usethink\console\Input;
usethink\console\Output;
usethink\console\input\Argument;
usethink\console\input\Option;
usethink\Db;
usethink\facade\Hook;
usethink\facade\Log;
useQL\QueryList;

classQueryListSpiderSingleextendsCommand{

    protectedfunctionconfigure(){
        $this->setName('querylist:single')
            ->setDescription('采集');
    }

    protectedfunctionexecute(Input $input, Output $output){
        ini_set('memory_limit', '512M');

        $output->writeln("=========date:" . date('Y-m-d H:i:s') . "===============");

        // 北橋蘇奧特曼//$slImgsUrl = "https://zhuanlan.zhihu.com/p/377571373";
        $slImgsUrl = "https://zhuanlan.zhihu.com/p/344680014";

        // 原生query_list
        $list = QueryList::get($slImgsUrl)->find('.RichText')->find('noscript')->find('img')->attrs('src');

        $path = 'E:\2setsoft\1dev\phpstudy_pro\WWW\4test\tensorflowJs\js-ml-code\t7\動漫分類\train\奧特曼\\';
        foreach($list as $key => $value) {
            $index = $key + 1 + 42;

            $filename = $index < 10 ? str_pad($index, 2, "0", STR_PAD_LEFT) : $index;
            $filend = pathinfo($value, PATHINFO_EXTENSION);
            $file = file_get_contents($value);
            file_put_contents($path . $filename . "." . $filend, $file);

            $output->writeln($index . "--" . $value . "已儲存--");
        }

        $output->writeln("============date:" .date("Y-m-d H:i:s") . "采集完成==============");
    }
    
}
           

2. 多線程采集

<?php/**
 * @Notes: 檔案描述
 * @Interface getCondition
 * @Return mixed
 * @Author: bqs
 * @Time: 2021/4/19 15:28
 */namespaceapp\common\command;

usethink\console\Command;
usethink\console\Input;
usethink\console\Output;
usethink\console\input\Argument;
usethink\console\input\Option;
usethink\Db;
usethink\facade\Hook;
usethink\facade\Log;
useQL\QueryList;
useQL\Ext\CurlMulti;

classQueryListSpiderextendsCommand{

    protectedfunctionconfigure(){
        $this->setName('query:list')
            ->setDescription('采集');
    }

    protectedfunctionexecute(Input $input, Output $output){
        ini_set('memory_limit', '512M');

        $output->writeln("=========date:" . date('Y-m-d H:i:s') . "===============");

        // 位址與目錄映射
        $dirMap = [
            "假面騎士" => "https://zhuanlan.zhihu.com/p/376119915",
            "龍珠" => "https://zhuanlan.zhihu.com/p/340048917",
            "火影忍者" => ["https://zhuanlan.zhihu.com/p/352717188", "https://zhuanlan.zhihu.com/p/393213201", "https://zhuanlan.zhihu.com/p/358228745"],
            "海賊王" => ["https://zhuanlan.zhihu.com/p/357683518", "https://zhuanlan.zhihu.com/p/338160632"]
        ];

        // 采集位址
        $multiArr = [];
        $multiArr = array_reduce(array_values($dirMap), function($res, $value){
            $res = array_merge($res, (array)$value);
            return $res;
        }, []);

        // 采集映射
        $multiMap = [];
        foreach($dirMap as $key => $value) {
            if (!is_array($value)) {
                $multiMap[$value] = $key;
            } else {
                $temp = array_fill_keys($value, $key);
                $multiMap = array_merge($multiMap, $temp);
            }
        }

        // 開始使用多線程采集
        $ql = QueryList::use (CurlMulti::class);
        $ql->curlMulti($multiArr)
        ->success(function(QueryList $ql, CurlMulti $curl, $r)use($multiMap){

            $path = 'E:\2setsoft\1dev\phpstudy_pro\WWW\4test\tensorflowJs\js-ml-code\t7\動漫分類\train\\';
            $queryUrl = $r['info']['url'];
            $className = $multiMap[$queryUrl] ?? "";
            $targetDir = $path . $className;
            $path = $targetDir . '\\';

            $endFileIndex = 0;
            $existFileList = $this->scanFile($targetDir);
            if ($existFileList) {
                // 取出所有數字檔案名最大值
                $endFileName = max($existFileList);
                $endFileIndex = explode(".", $endFileName)[0];
            }

            $data = $ql->find('.RichText')->find('noscript')->find('img')->attrs('src');

            foreach($data as $key => $value) {
                $index = $key + 1 + $endFileIndex;

                $filename = $index < 10 ? str_pad($index, 2, "0", STR_PAD_LEFT) : $index;
                $filend = pathinfo($value, PATHINFO_EXTENSION);
                $file = file_get_contents($value);
                file_put_contents($path . $filename . "." . $filend, $file);
            }
        })
        // 每個任務失敗回調
        ->error(function($errorInfo, CurlMulti $curl){
            echo"Current url:{$errorInfo['info']['url']} \r\n";
            print_r($errorInfo['error']);
        })
        ->start([
            // 最大并發數'maxThread' => 10,
            // 錯誤重試次數'maxTry' => 5,
        ]);

        $output->writeln("============date:" . date("Y-m-d H:i:s") . "采集完成==============");
    }

    // 掃描目錄下所有檔案protectedfunctionscanFile($path){
        $result = [];
        $files = scandir($path);
        foreach ($files as $file) {
            if ($file != '.' && $file != '..') {
                if (is_dir($path . '/' . $file)) {
                    $this->scanFile($path . '/' . $file);
                } else {
                    $result[] = basename($file);
                }
            }
        }
        return $result;
    }

}
           

問題解決:

由于普通采集的請求使用 GuzzleHttp 用戶端,而多線程采集是 CURL,是以運作時報 curl 狀态碼 60 錯誤。

用 tensorflow.js 做了一個動漫分類的功能(一)

1. 解決方法:

(1). 下載下傳 cacert

下載下傳位址:https://curl.haxx.se/ca/cacert.pem

(2). 修改 php.ini , 并重新開機

在 php.ini 中找到 curl.cainfo 改為檔案的絕對路徑如:curl.cainfo =E:\2setsoft\1dev\phpstudy_pro\Extensions\php\php7.4.3nts\cacert.pem

用 tensorflow.js 做了一個動漫分類的功能(一)

圖檔訓練:

以上的圖檔已經采集的差不多了,因為部落客的圖檔有限,我也沒有再去其他地方找,整個檔案夾下的圖檔在 200 張左右。按理說圖檔當然是越多越好,但是整個分類标注起來耗時(看文章的配圖,應該已經知道有哪幾類了吧),是以就這樣了。最後就是讀取圖檔轉換 Tensor 進行訓練,後一篇再具體介紹吧,提醒一下。下一篇需要提前安裝 Node, Http-Server,Parcel 工具。

用 tensorflow.js 做了一個動漫分類的功能(一)