データ拡張コードの実践、マルチプロセスとマルチスレッドに関する知識ポイントを追加します。

  • 現在、最も先進的なニューラル ネットワーク モデルは、一連の線形関数と非線形関数を使用してターゲット出力に適合します。当然のことながら、フィッティングするのでサンプル数が多ければ多いほど、より正確な結果が得られるため、ニューラル ネットワークの学習に使用されるデータの規模はますます大きくなっています。

  • 実際の使用では、データが数千、場合によっては数百しかないことがよくあります。ニューラル ネットワークの何百万ものパラメータに直面すると、過学習の罠に陥りやすくなります。ニューラル ネットワークの収束には長いトレーニング プロセスが必要であり、このプロセス中にネットワークはトレーニング セット内の同じ少数の画像に何度も遭遇するため、それらを記憶することで何が一般化できるかを学習するのは困難であるためです。自然に考えられるのは、1 つの画像を使用して一連の画像を生成し、それによってデータ セットを何百倍、何千倍にも拡張できるだろうか、ということです。これがデータ強化の目的の 1 つです。

  • ニューラル ネットワークには常識がないため、常に最も「便利な」方法で 2 つのカテゴリを区別します。リンゴとオレンジを区別するようにニューラル ネットワークをトレーニングしたいとします。しかし、私たちが持っているデータは赤いリンゴと緑のオレンジだけです。どれだけ写真を撮っても、ニューラル ネットワークは単に赤いものがリンゴで、シアンのものがリンゴであると判断します。オレンジ。これは実際の使用においてもよく起こることであり、照明や撮影角度などの目立たない点を基にニューラルネットワークが分類します。

  • データ強化の目的は、むやみにデータを積み上げることではなく、元のデータではカバーできない現実に起こりうる事態を可能な限りカバーすることですデータ拡張技術を使用すると、データセット内の画像の多様性が高まり、それによってモデルのパフォーマンスと一般化能力が向上します。Pytorch フレームワークでは、一般的に使用されるデータ拡張機能は主に変換ファイルに統合されており、変換の入力は PIL ファイル形式であるため、PIL.Image モジュールを使用する必要があります

  • ガイドパッケージ:

    • from PIL import Image
      from pathlib import Path
      import matplotlib.pyplot as plt
      import torch
      import numpy as np
      plt.rcParams["savefig.bbox"]="tight"
      org_img=Image.open(Path("nest.jpg"))
      torch.manual_seed(0)
      print(np.array(org_img).shape) 
      # (2286, 2603, 3)
      
    • サイズ変更、ズーム

    • import torchvision.transforms as T
      resize_img=[T.Resize(size=newsize)(org_img) for newsize in [1000,2000]]
      
      ax1=plt.subplot(131)
      ax1.set_title("original")
      ax1.imshow(org_img)
      
      ax2=plt.subplot(132)
      ax2.set_title("1000*1000")
      ax2.imshow(resize_img[0])
      
      ax3=plt.subplot(133)
      ax3.set_title(2000*2000)
      ax3.imshow(resize_img[1])
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • グレースケール

    • gray_img = T.Grayscale()(org_img)
      ax1 = plt.subplot(121)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(122)
      ax2.set_title('gray')
      ax2.imshow(gray_img,cmap='gray')
      plt.show()
      
    • ここに画像の説明を挿入します

    • 標準化

    • norm_img=T.Normalize(mean=(0.5,0.5,0.5),std=(0.5,0.5,0.5))(T.ToTensor()(org_img))
      norm_img=[T.ToPILImage()(norm_img)]
      
      ax1 = plt.subplot(121)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(122)
      ax2.set_title('normalize')
      ax2.imshow(norm_img[0])
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • 回転させる

    • plt.rcParams['font.sans-serif'] = ['SimHei']
      rotate_img=[T.RandomRotation(degrees=180)(org_img)]
      # print(rotate_img)
      
      ax1=plt.subplot(121)
      ax1.set_title("original")
      ax1.imshow(org_img)
      
      ax2=plt.subplot(122)
      ax2.set_title("$180$")
      ax2.imshow(rotate_img[0])
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • センタークロップ

    • center_crop=[T.CenterCrop(size=newsize)(org_img) for newsize in (300,600)]
      
      ax1 = plt.subplot(131)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(132)
      ax2.set_title('300*300')
      ax2.imshow(np.array(center_crop[0]))
      
      ax3 = plt.subplot(133)
      ax3.set_title('600*600')
      ax3.imshow(np.array(center_crop[1]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • ランダムな収穫

    • rand_corp=[T.RandomCrop(size=newsize)(org_img) for newsize in [500,1000]]
      
      ax1 = plt.subplot(131)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(132)
      ax2.set_title('500*500')
      ax2.imshow(np.array(rand_corp[0]))
      
      ax3 = plt.subplot(133)
      ax3.set_title('1000*1000')
      ax3.imshow(np.array(rand_corp[1]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • ガウスノイズを追加する

    • blur_img=[T.GaussianBlur(kernel_size=(3,3),sigma=x)(org_img) for x in (30,60)]
      
      ax1 = plt.subplot(131)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(132)
      ax2.set_title('sigma=30')
      ax2.imshow(np.array(blur_img[0]))
      
      ax3 = plt.subplot(133)
      ax3.set_title('sigma=60')
      ax3.imshow(np.array(blur_img[1]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • 色補正、彩度など

    • colorjitter=[T.ColorJitter(brightness=(0.2,0.8),contrast=(0.5,0.5),saturation=(0.5,0.5),hue=0.5)(org_img)]
      # 亮度(brightness)、对比度(contrast)、饱和度(saturation)和色调(hue)
      # brightness_factor从[max(0, 1 - brightness), 1 + brightness]中随机采样产生。应当是非负数。
      # contrast_factor从[max(0, 1 - contrast), 1 + contrast]中随机采样产生。应当是非负数。
      # saturation_factor从[max(0, 1 - saturation), 1 + saturation]中随机采样产生。应当是非负数。
      # hue_factor从[-hue, hue]中随机采样产生,其值应当满足0<= hue <= 0.5或-0.5 <= min <= max <= 0.5
      ax1 = plt.subplot(121)
      ax1.set_title('original')
      ax1.imshow(org_img)
      ax2 = plt.subplot(122)
      ax2.set_title('colorjitter')
      ax2.imshow(np.array(colorjitter[0]))
      plt.show()
      
    • ここに画像の説明を挿入します

    • 水平反転

    • horizon=[T.RandomHorizontalFlip(p=1)(org_img)]
      # p表示概率
      ax1 = plt.subplot(121)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(122)
      ax2.set_title('horizon')
      ax2.imshow(np.array(horizon[0]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • 垂直方向に反転

    • vertical=[T.RandomVerticalFlip(p=1)(org_img)]
      
      ax1 = plt.subplot(121)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(122)
      ax2.set_title('VerticalFlip')
      ax2.imshow(np.array(vertical[0]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • カスタムノイズを追加する

    • def add_noise(imputs,noise_fac=0.5):
          noise=imputs + torch.randn_like(imputs)*noise_fac
          noise=torch.clip(noise,0.0,1.0)
          # clip这个函数将将数组中的元素限制在a_min, a_max之间,大于a_max的就使得它等于 a_max,小于a_min,的就使得它等于a_min。
          return noise
      
      noise_img=[add_noise(T.ToTensor()(org_img),fac) for fac in (0.4,0.8)]
      noise_img=[T.ToPILImage()(n_img) for n_img in noise_img]
      
      ax1 = plt.subplot(131)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(132)
      ax2.set_title('noise_factor=0.4')
      ax2.imshow(np.array(noise_img[0]))
      
      ax3 = plt.subplot(133)
      ax3.set_title('noise_factor=0.8')
      ax3.imshow(np.array(noise_img[1]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • マスクブロックを追加

    • def add_box(img,num_box,size=100):
          h,w=size,size
          img=np.asarray(img).copy()
          img_size=img.shape[1]
          boxes=[]
          for k in range(num_box):
              y,x=np.random.randint(0,img_size-w,(2,))
              img[y:y+h,x:x+w]=0
              boxes.append((x,y,h,w))
          img=Image.fromarray(img.astype('uint8'),'RGB')
          return img
      
      block_img=[add_box(org_img,num_box=15)]
      
      ax1 = plt.subplot(121)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(122)
      ax2.set_title('add black boxes')
      ax2.imshow(np.array(block_img[0]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

    • センターマスクブロック

    • def add_center(o_img,size=150):
          h,w=size,size
          img=np.asarray(o_img).copy()
          img_size=img.shape[1]
          img[int(img_size/2-h):int(img_size/2+h),int(img_size/2-w):int(img_size/2+w)]=0
          img=Image.fromarray(img.astype('uint8'),'RGB')
          return img
      
      center_img=[add_center(org_img,size=200)]
      
      ax1 = plt.subplot(121)
      ax1.set_title('original')
      ax1.imshow(org_img)
      
      ax2 = plt.subplot(122)
      ax2.set_title('add_center')
      ax2.imshow(np.array(center_img[0]))
      
      plt.show()
      
    • ここに画像の説明を挿入します

マルチプロセスとマルチスレッド

  • 同時実行性: 一定期間にわたる交互に複数のタスクを実行します。例: シングルコア CPU が複数のタスクを処理する場合、オペレーティング システムは順番に各タスクを実行します。代替実行

  • 並列処理: 複数のタスクを一定期間にわたって同時に同時に実行すること例: マルチコア CPU がマルチタスクを処理できるように、オペレーティング システムは CPU の各コアが実行するタスクを配置します。複数のコアは実際に複数のタスクを同時に実行できます。ここで必要ですマルチコア CPU は複数のタスクを並行して実行し、複数のタスクは常に一緒に実行されることに注意してください。

  • プロセスはオペレーティング システムがリソースを割り当てる最小単位であり、スレッドはオペレーティング システムがスケジュールする最小単位です。(1 つは割り当て用、もう 1 つはスケジュール用)

  • アプリケーションには少なくとも 1 つのプロセスが含まれ、1 つのプロセスには 1 つ以上のスレッドが含まれ、スレッドのサイズは小さくなります。

  • 各プロセスは実行中に独立したメモリ ユニットを持ち、プロセスの複数のスレッドが実行中にメモリを共有します。

  • 工場(CPU に似たもの) は、電力が制限されており、1 つのワークショップのみを供給できる、つまり 1 つのタスクしか実行できないことを前提としています。単一のタスクを実行するために、その中には多数のワークショップ (プロセスに似たもの)があります。この場合、一度に実行できるワークショップは 1 つだけです。別のワークショップが動作したい場合は、現在のワークショップを休ませる必要があります。

  • マルチコア CPU は複数の工場のようなものです。複数のワークショップ (複数のプロセスに似ています) が同時に連携して動作することができます。もちろん、それらは異なる工場で動作します。つまり、異なる CPU コアで実行されます。

  • 各ワークショップには多数のワーカーがあり、スレッドと同様です。ワークショップには複数のワーカー、つまりプロセスには複数のスレッドを含めることができます。

  • これが CPU、マルチコア、プロセス、スレッドの基本的な関係です。ここではすべてが調和しているようで、ロックとは何の関係もありません。なぜ社会には鍵がかかるのか?次に、メモリ使用量の問題について話さなければなりません。

    • プロセスの下では、そのプロセスが持つリソースは限られており (たとえば、いくつなど)、このプロセスの下では、ワークショップと同じように、複数のスレッドがこれらのリソースを共有し、それぞれのサイズが異なります。ワーカーが作業のために異なる場所を占有している場合はどうすればよいでしょうか?次に、鍵を追加する必要があります。ある作業場所が満員の場合、ここに人が入る余地がないことを他の従業員に伝えるために、鍵を設置する必要があります。誰かが戻ってくるまで、つまり、特定のスレッドがメモリの解放を完了してから、誰かが再び入ってきて新しいスレッドを開始するまで待たなければなりません。

    • ここで大手企業は、相互排除 (Mutex)と呼ばれる、競合を防ぐ簡単な方法を発明しました言い換えれば、スレッドが共有メモリを使用するときは、他の人が入ってきて占有できないようにドアをロックします。後から来た人は、ロックが解除される、つまりスペースが解放されるまで待たなければ、再びそのスペースに入って使用することはできません。

    • 同時にn名様までご利用いただけるお部屋もございます。つまり、人数がn人より多い場合、余った人は外で待つしかありません。これは、固定数のスレッドのみが使用できるメモリ領域のようなものです。現時点での解決策は、ドアに n 個の鍵を掛けることです。入った人は鍵を受け取り、出てくるときにその鍵を掛け直します。後から到着した人たちは、鍵が空であることに気づき、ドアのところで列に並ばなければならないことを悟りましたこのアプローチは「セマフォ」と呼ばれ、複数のスレッドが互いに競合しないようにするために使用されます。

  • マルチプロセスCPU はリソースを自動的に割り当て、異なるコアで同時に実行できます。Python のマルチスレッドは、実際には CPU 上で断続的に動作し、1 つのスレッドが実行されると他のスレッドは休止状態になり、次のスレッドが開始されると、他のスレッドは再び休止状態になります。

  • マルチスレッド: CPU と IO を同時に実行できるという原理を使用したスレッド化。これにより、CPU は IO の完了をむやみに待たなくなります。

    • マルチスレッド スレッド (スレッド化) の利点:プロセスと比較して軽量で、使用するリソースが少なくなります欠点: コルーチンと比較して、マルチスレッドは同時実行のみが可能であり、複数の CPU (GIL) を利用できないコルーチンと比較して: 起動回数が制限され、メモリ リソースが占有され、スレッド切り替えのオーバーヘッドが発生します。最適な用途: IO 集中型のコンピューティング。同時に実行するタスクの数は必要ありません。
  • マルチプロセス: マルチプロセッシング。マルチコア CPU の機能を利用してタスクを実際に並列実行します。

    • マルチプロセスプロセス(マルチプロセッシング)・メリット:マルチコアCPUによる並列計算が利用可能短所: ほとんどのリソースを消費し、開始可能なスレッドがスレッドよりも少なく、次の用途に適しています。 CPU 負荷の高い計算
  • 非同期 IO: asyncio は、単一スレッドでの CPU と IO の同時実行の原理を使用して、関数の非同期実行を実現します。

    • マルチコルーチン コルーチン (asyncio) の利点:メモリ オーバーヘッドが最小限であり、開始されるコルーチンの数が最大です短所: サポートされるライブラリは限られており (aiohttp とリクエスト)、コードの実装は複雑です。最適な用途: IO 集中型のコンピューティング、超マルチタスクを必要とするが既製のライブラリでサポートされるシナリオ
  • 1 つのプロセス内に複数のスレッドが存在する可能性があり、1 つのスレッド内に複数のコルーチンが存在する可能性があります。

  • Lock を使用してリソースをロックし、アクセスの競合を防ぎます。

  • キューを使用して、異なるスレッド/プロセス間のデータ通信を実装し、プロデューサー/コンシューマー モデルを実装します。

  • スレッド プール/プロセス プール プールを使用して、スレッド/プロセス タスクの送信、完了の待機、および結果の取得を簡素化します。

  • サブプロセスを使用して外部プログラムのプロセスを開始し、入出力の対話を実行します。

  • CPU 集約型とは、コンピューティング集約型とも呼ばれ、I/O が短時間で完了することを意味し、多くの計算と処理が必要となり、CPU 使用率が非常に高いという特徴があります。

    • 例: 圧縮と解凍、暗号化と復号化、正規表現検索
  • I/O 集中型とは、システム動作のほとんどが CPU が I/O (ハードディスク/メモリ) の読み取り/書き込み操作を待機しているときに行われ、CPU 使用率がまだ低いことを意味します。

    • 例: ファイル処理プログラム、Web クローラー プログラム、データベース プログラムの読み取りおよび書き込み
  • グローバル インタープリター ロック(英語: Global Interpreter Lock、略称 GIL)とは、コンピュータ プログラミング言語のインタープリターがスレッドを同期するために使用する機構で、常に 1 つのスレッドのみを実行できるようにします。マルチコア プロセッサ上でも、GIL を使用するインタープリタでは一度に 1 つのスレッドしか実行できませんGIL により、共有リソースの管理が簡素化されます。

    • Python スレッドは実際のスレッドですが、インタープリタがコードを実行するときは、GIL ロック (グローバル インタープリタ ロック) が存在します。Python スレッドが実行される前に、最初に GIL ロックを取得する必要があります。その後、100 バイトコードが実行されるたびに、インタープリタはGIL ロックは自動的に解放され、他のスレッドが実行できるようになりますこのGILグローバルロックは実際には全スレッドの実行コードをロックするため、Pythonではマルチスレッドを交互に実行することしかできず、100コアのCPUで100スレッドが動作しても1コアしか使用できません。
  • マルチスレッド メカニズムは、IO 集中型の計算に依然として役立ちます。I/O (読み取り、書き込み、送信、受信など) 中に、スレッドは GIL を解放してCPU と IO の並列化を実現するため、IO 集中型の計算にマルチスレッドを使用すると、速度が大幅に向上します。ただし、CPU 負荷の高い計算にマルチスレッドを使用すると、速度がさらに低下するだけです

  • 使用マルチプロセッシングのマルチプロセッシングの仕組み並列コンピューティングを実現し、マルチコア CPU を活用します。GIL の問題に対処するために、Python はマルチプロセッシングを提供します。

  • ここに画像の説明を挿入します

  • 新しいスレッドシステムはリソースを割り当て、終了したスレッドシステムはリソースを回収する必要がありますが、スレッドを再利用できれば新規作成・終了のオーバーヘッドを軽減できます。スレッドの実行時間は、スレッドの起動時間、スレッド本体の実行時間、スレッドの破棄時間の 3 つの部分に分けることができます。マルチスレッド処理のコンテキストでは、スレッドを再利用できない場合、各作成は開始、破棄、実行の 3 つのプロセスを経る必要があることを意味します。これにより、必然的にシステムの応答時間が増加し、効率が低下します。

  • ここに画像の説明を挿入します

  • スレッド プールを使用する利点 1. パフォーマンスの向上: スレッドの作成と終了にかかる大量のオーバーヘッドが削減されるため、スレッド リソースが再利用されます; 2. 適用可能なシナリオ: 突然の大量のリクエストの処理または大量のリクエストの処理に適しています。タスクを完了するためにスレッドを使用しますが、実際のタスクの処理時間は短くなります; 3. 防御機能:システムが過剰なスレッドを作成し、システムが過負荷になって速度が低下することを効果的に防止できます; 4. コードの利点: 構文を使用します。スレッド プールの作成は、新しいスレッド実行スレッドを自分で作成するよりも簡潔です

  • スレッド プールを使用する:スレッドは事前に作成されてスレッド プールに入れられ、現在のタスクの処理後に破棄されるのではなく、次のタスクを処理するように配置されるため、スレッドを複数回作成することを回避でき、オーバーヘッドを節約できます。スレッドの作成と破棄を抑制することで、パフォーマンスとシステムの安定性を向上させることができますスレッド プールの基本原理: タスクをキューに入れ、N 個のスレッドを開きます。各スレッドはタスクを取得するためにキューに移動します。タスクを実行した後、タスクの実行が終了したことをシステムに伝えます。キュー内のすべてのタスクが空になり、スレッドが終了するまで、キューから次のタスクをフェッチします。

  • ここに画像の説明を挿入します

  • # 创建队列实例, 用于存储任务
    queue = Queue()
    # 定义需要线程池执行的任务
    def do_job():
        while True:
            i = queue.get()
            time.sleep(1)
            print 'index %s, curent: %s' % (i, threading.current_thread())
            queue.task_done()
    if __name__ == '__main__':
        # 创建包括3个线程的线程池
        for i in range(3):
            t = Thread(target=do_job)
            t.daemon=True # 设置线程daemon  主线程退出,daemon线程也会推出,即时正在运行
            t.start()
        # 模拟创建线程池3秒后塞进10个任务到队列
        time.sleep(3)
        for i in range(10):
            queue.put(i)
        queue.join()
    
  • Python でのマルチスレッドとマルチプロセスのサポート

  • ここに画像の説明を挿入します

  • セマフォ(英語: Semaphore )は、セマフォやセマフォとも呼ばれ、カウント値を 0 から指定された最大値までの間で維持するために使用される同期オブジェクトです。スレッドがセマフォ オブジェクトの待機を完了すると、カウント値は 1 減少し、スレッドがセマフォ オブジェクトの解放を完了すると、カウント値は 1 増加します。カウント値が 0 の場合、スレッドはセマフォ オブジェクトがシグナル状態になるまでセマフォ オブジェクトを待つことができなくなります。セマフォ オブジェクトのカウント値は 0 (シグナル状態) より大きく、カウント値は以下に等しいです。 0、これは信号のない状態です。

  • メインプロセスデーモンを設定します: 子プロセス object.daemon=true。マルチスレッドは、Python プログラムでマルチタスクを実装する方法です。スレッドはプログラム実行の最小単位です。同じプロセスに属する複数のスレッドは、プロセスが所有するすべてのリソースを共有します。

おすすめ

転載: blog.csdn.net/weixin_43424450/article/details/133269326