1. 程式人生 > >網上爬取圖片製作成資料集進行訓練

網上爬取圖片製作成資料集進行訓練

一、用pthon爬取圖片

如圖:

建立一個資料夾,下放每一類的資料夾(我的絕對路徑是:/home/user/dataset/)

 在每一個class下面,建立一個test.py檔案,用以爬取圖片

# coding=utf-8
"""根據搜尋詞下載百度圖片"""
import re
import sys
import urllib

import requests


def get_onepage_urls(onepageurl):
    """獲取單個翻頁的所有圖片的urls+當前翻頁的下一翻頁的url"""
    if not onepageurl:
        print('已到最後一頁, 結束')
        return [], ''
    try:
        html = requests.get(onepageurl).text
    except Exception as e:
        print(e)
        pic_urls = []
        fanye_url = ''
        return pic_urls, fanye_url
    pic_urls = re.findall('"objURL":"(.*?)",', html, re.S)
    fanye_urls = re.findall(re.compile(r'<a href="(.*)" class="n">下一頁</a>'), html, flags=0)
    fanye_url = 'http://image.baidu.com' + fanye_urls[0] if fanye_urls else ''
    return pic_urls, fanye_url


def down_pic(pic_urls):
    """給出圖片連結列表, 下載所有圖片"""
    for i, pic_url in enumerate(pic_urls):
        try:
            pic = requests.get(pic_url, timeout=15)
            string = str(i + 1200) + '.jpg'
            with open(string, 'wb') as f:
                f.write(pic.content)
                print('成功下載第%s張圖片: %s' % (str(i + 1), str(pic_url)))
        except Exception as e:
            print('下載第%s張圖片時失敗: %s' % (str(i + 1), str(pic_url)))
            print(e)
            continue


if __name__ == '__main__':
    keyword = '膝上型電腦'  # 關鍵詞, 改為你想輸入的詞即可, 相當於在百度圖片裡搜尋一樣
    url_init_first = r'http://image.baidu.com/search/flip?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1497491098685_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&ctd=1497491098685%5E00_1519X735&word='
    url_init = url_init_first + urllib.parse.quote(keyword, safe='/')
    all_pic_urls = []
    onepage_urls, fanye_url = get_onepage_urls(url_init)
    all_pic_urls.extend(onepage_urls)

    fanye_count = 1  # 累計翻頁數
    while 1:
        onepage_urls, fanye_url = get_onepage_urls(fanye_url)
        fanye_count += 1
        print('第%s頁' % fanye_count)
        if fanye_url == '' and onepage_urls == []:
            break
        all_pic_urls.extend(onepage_urls)

    down_pic(list(set(all_pic_urls)))

基本上只需要改變keyword和命名就可以以每次60張圖片的速度進行爬取。

具體命令如下:

cd /home/user/dataset/class0

python test.py

在下載過程中會有提示,class1也是一樣。下載完批量的圖片以後就要開始選擇要用什麼框架訓練資料集。(因為一直在學習mxnet,所以選擇了mxnet,mxnet主要將圖片資料生成rec檔案,有一個im2rec.py專門將圖片生成rec檔案,具體步驟如下:

1)生成lst檔案

recursive:是否遞迴訪問子目錄,如果存在多個目錄可以設定該引數
list::指令碼預設為False,所以製作lst時應設定為True
prefix:需要生成的lst檔案的字首(這裡我命名為test,就會生成test.lst)
root:指定資料集的根目錄,其子目錄為圖片或進一步的子目錄(注意:路徑一定要寫對!!!)

終端命令為:python ~/mxnet/tools/im2rec.py --recursive --list test /home/user/dataset/

隨後,在我的目錄下面就生成了lst檔案

開啟lst檔案是這樣的:

第一行是圖片大小,中間是類別,後面是相對路徑

2)生成rec檔案

涉及引數:
–list 是否建立list檔案,預設為False
–exts 所能接受的圖片字尾,預設為jpg和jpeg(如果圖片是png格式,可以對im2rec.py檔案進行修改)
–chunks 分塊數量,預設為1
–train-ratio 訓練集所佔的比例,預設為1.0
–test-ratio 測試集所佔的比例,預設為0
–recursive 是否遞迴的對root下的資料夾進行遍歷
–shuffle 是否打亂list中的圖片順序,預設為True
–pass-through 是否跳過transform,預設為False
–resize 是否將短邊縮放至設定尺寸,預設為0
–center-crop 是否進行中心剪裁,預設為False
–quality 圖片解碼質量(0-100),預設為95
–num-thread 編碼的執行緒數,預設為1
–color 色彩解碼模式[-1,0,1],-1為彩色模式,0為灰度模式,1為alpha模式,預設為1
–encoding 解碼模式(jpeg,png),預設為jpeg
–pack-label 是否讀入多維度標籤資料,預設為False 如果進行多標籤資料製作或者目標檢測的資料製作,那麼就必須將其設定為True

終端命令:python ~/mxnet/tools/im2rec.py --recursive test /home/user/dataset/

然後就在該路徑下生成了一個rec字尾和一個idx檔案,裡面是bin格式,所以一般打不開。這裡就不打開了。

截圖:

生成了rec檔案以後,就需要在網路中訓練了。

import sys
sys.path.insert(0, '..')

import gluonbook as gb
import mxnet as mx
from mxnet import autograd, nd, gluon, init
from mxnet.gluon import loss as gloss, nn
from time import time
import os
from skimage import io  
import numpy as np

class Residual(nn.HybridBlock):
    def __init__(self, num_channels, use_1x1conv=False, strides=1, **kwargs):
        super(Residual, self).__init__(**kwargs)
        self.conv1 = nn.Conv2D(num_channels, kernel_size=3, padding=1,
                               strides=strides)
        self.conv2 = nn.Conv2D(num_channels, kernel_size=3, padding=1)
        if use_1x1conv:
            self.conv3 = nn.Conv2D(num_channels, kernel_size=1,
                                   strides=strides)
        else:
            self.conv3 = None
        self.bn1 = nn.BatchNorm()
        self.bn2 = nn.BatchNorm()

    def hybrid_forward(self, F, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
            X = self.conv3(X)
        return F.relu(Y + X)

def resnet18(num_classes):
    net = nn.HybridSequential()
    net.add(nn.Conv2D(64, kernel_size=3, strides=1, padding=1),
            nn.BatchNorm(), nn.Activation('relu'))

    def resnet_block(num_channels, num_residuals, first_block=False):
        blk = nn.HybridSequential()
        for i in range(num_residuals):
            if i == 0 and not first_block:
                blk.add(Residual(num_channels, use_1x1conv=True, strides=2))
            else:
                blk.add(Residual(num_channels))
        return blk

    net.add(resnet_block(64, 2, first_block=True),
            resnet_block(128, 2),
            resnet_block(256, 2),
            resnet_block(512, 2))
    net.add(nn.GlobalAvgPool2D(), nn.Dense(num_classes))
    return net

def get_net(ctx):
    num_classes = 2
    net = resnet18(num_classes)
    net.initialize(ctx=ctx, init=init.Xavier())
    return net

batch_size = 32

train_iter = mx.image.ImageIter(  
    batch_size = batch_size,  
   data_shape = (3, 256,256),  
   path_imgrec = 'test.rec',  
   path_imgidx = 'test.idx',  #help shuffle performance
   shuffle = True,
   #aug_list=[mx.image.HorizontalFlipAug(0.5)]  
)

train_iter.reset()  
for batch in train_iter:  
    x = batch.data[0]
    y = batch.label[0]
    print(x)
    print('y is' ,y)
    break 

def try_gpu():
    try:
        ctx = mx.gpu()
        _ = nd.zeros((1,), ctx=ctx)
    except:
        ctx = mx.cpu()
    return ctx

ctx = try_gpu()
ctx

def evaluate_accuracy(data_iter, net, ctx):
    acc = nd.array([0], ctx=ctx)
    for X, y in data_iter:
        # 如果 ctx 是 GPU,將資料複製到 GPU 上。
        X = X.as_in_context(ctx)
        y = y.as_in_context(ctx)
        acc += gb.accuracy(net(X), y)
    return acc.asscalar() / len(data_iter)

def train_ch5(net, train_iter, loss, batch_size, trainer, ctx,
              num_epochs):
    print('training on', ctx)
    for epoch in range(1, num_epochs + 1):
        train_l_sum = 0
        train_acc_sum = 0
        start = time()
        for batch in train_iter:
            X = batch.data[0]
            y = batch.label[0]
            # 如果 ctx 是 GPU,將資料複製到 GPU 上。
            print(X,y)
            X = X.as_in_context(ctx)
            y = y.as_in_context(ctx)
            with autograd.record():
                net = get_net(ctx)
                y_hat = net(X)
                l = loss(y_hat, y)
            l.backward()
            trainer.step(batch_size)
            train_l_sum += l.mean().asscalar()
            train_acc_sum += gb.accuracy(y_hat, y)
        #test_acc = evaluate_accuracy(test_iter, net, ctx)
        print('epoch %d, loss %.4f, train acc %.3f, '
              'time %.1f sec'
              % (epoch, train_l_sum / len(train_iter),
                 train_acc_sum / len(train_iter), time() - start))

lr = 0.8
num_epochs = 5
net.initialize(force_reinit=True, ctx=ctx, init=init.Xavier())
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': lr})
loss = gloss.SoftmaxCrossEntropyLoss()
train_ch5(net, train_iter, loss, batch_size, trainer, ctx,
          num_epochs)

這裡簡單的用了resnet18作為網路進行訓練,大家可以使用適合自己資料集的網路進行訓練。 祝大家玩的愉快!有什麼問題可以一起探討~~