얼굴 및 성별 인식에 VGG 사용

Mary-Kate Olsen
풀어 주다: 2024-11-06 10:45:03
원래의
981명이 탐색했습니다.

Using VGGfor face and gender recognition

딥 러닝과 VGG16을 사용하여 얼굴 및 성별 인식 Python 프로젝트를 구축하는 방법

딥러닝이란 무엇인가요?

딥 러닝은 머신 러닝의 하위 범주로, 3개 이상의 레이어로 구성된 신경망입니다. 이러한 신경망은 대량의 데이터로부터 학습하여 인간 두뇌의 행동을 시뮬레이션하려고 합니다. 단일 레이어가 있는 신경망은 여전히 ​​대략적인 예측을 할 수 있지만 추가 숨겨진 레이어는 정확성을 위해 최적화하고 개선하는 데 도움이 될 수 있습니다.

딥 러닝은 사람의 개입 없이 작업을 수행하여 자동화를 향상시킵니다. 딥 러닝은 디지털 비서, 음성 지원 TV 리모컨, 신용카드 사기 감지, 자율주행차 등에서 찾아볼 수 있습니다.

Python 프로젝트 빌드

** GitHub에서 전체 코드를 확인하세요: https://github.com/alexiacismaru/face-recognision

얼굴 인식 작업의 전처리에 사용될 얼굴 감지에 사용되는 VGG16 얼굴 데이터 세트와 Haar Cascade XML 파일을 다운로드하세요.

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

VGG 얼굴 데이터세트에서 사전 정의된 피사체 세트에 대해 특정 개수의 이미지를 선택적으로 로드하고 처리합니다.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

주제와 관련된 텍스트 파일을 열고 내용을 읽어 각 주제의 파일을 반복합니다. 이 파일의 각 줄에는 이미지에 대한 URL이 포함되어 있습니다. 이미지를 가리키는 각 URL에 대해 코드는 urllib를 사용하여 이미지를 로드하고 이를 NumPy 배열로 변환하려고 시도합니다.

images = []

for subject in all_subjects[:nb_subjects]:
  with open(os.path.join(base_path, "vgg_face_dataset", "files", subject), 'r') as f:
    lines = f.readlines()

  images_ = []
  for line in lines:
    url = line[line.find("http://"): line.find(".jpg") + 4]

    try:
      res = request.urlopen(url)
      img = np.asarray(bytearray(res.read()), dtype="uint8")
      # convert the image data into a format suitable for OpenCV
      # images are colored 
      img = cv2.imdecode(img, cv2.IMREAD_COLOR)
      h, w = img.shape[:2]
      images_.append(img)
      cv2_imshow(cv2.resize(img, (w // 5, h // 5)))

    except:
      pass

    # check if the required number of images has been reached
    if len(images_) == nb_images_per_subject:
      # add the list of images to the main images list and move to the next subject
      images.append(images_)
      break
로그인 후 복사
로그인 후 복사

얼굴 인식 설정

Using VGGfor face and gender recognition

  1. 이미지에서 하나 이상의 얼굴을 찾아 상자에 넣으세요.
  2. 얼굴이 기하학, 측광 등 데이터베이스와 일치하는지 확인하세요.
  3. 인식 작업에 사용할 수 있는 얼굴 특징을 추출합니다.
  4. 준비된 데이터베이스에 있는 하나 이상의 알려진 얼굴과 얼굴을 연결하세요.
# create arrays for all 4 celebrities
jesse_images = []
michael_images = []
mila_images = []
sarah_images = []

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontalface_default.xml"))

# iterate over the subjects
for subject, images_ in zip(all_subjects, images):

  # create a grayscale copy to simplify the image and reduce computation
  for img in images_:
    img_ = img.copy()
    img_gray = cv2.cvtColor(img_, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(
        img_gray,
        scaleFactor=1.2,
        minNeighbors=5,
        minSize=(30, 30),
        flags=cv2.CASCADE_SCALE_IMAGE
    )
    print("Found {} face(s)!".format(len(faces)))

    for (x, y, w, h) in faces:
        cv2.rectangle(img_, (x, y), (x+w, y+h), (0, 255, 0), 10)

    h, w = img_.shape[:2]
    resized_img = cv2.resize(img_, (224, 224))
    cv2_imshow(resized_img)

    if "Jesse_Eisenberg" in subject:
        jesse_images.append(resized_img)
    elif "Michael_Cera" in subject:
        michael_images.append(resized_img)
    elif "Mila_Kunis" in subject:
        mila_images.append(resized_img)
    elif "Sarah_Hyland" in subject:
        sarah_images.append(resized_img)
로그인 후 복사
로그인 후 복사

DetectMultiScale 방법은 이미지 속 얼굴을 인식합니다. 그런 다음 얼굴이 있다고 생각되는 직사각형의 좌표를 반환합니다. 각 얼굴에 대해 이미지 주위에 직사각형이 그려져 얼굴의 위치를 ​​나타냅니다. 각 이미지는 224x224픽셀로 크기가 조정되었습니다.

데이터세트를 훈련 및 검증 세트로 분할:

  • 훈련 세트는 기계 학습 모델을 훈련하는 데 사용됩니다. 데이터 내의 패턴, 특징 및 관계를 학습하는 데 사용됩니다. 모델은 훈련 데이터에 대한 예측 또는 분류의 오류를 최소화하기 위해 매개변수를 조정합니다.
  • 검증 세트는 새로운 데이터 세트에 대한 모델의 성능을 평가합니다. 이는 모델이 보이지 않는 데이터에 얼마나 잘 일반화되는지 확인하는 데 도움이 됩니다. 검증 세트는 모델 학습 중에 사용되지 않는 독립적인 세트여야 합니다. 훈련 중에 검증 세트의 정보를 혼합/사용하면 결과가 왜곡될 수 있습니다.
faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

데이터 증대

딥 러닝 모델의 정확성은 훈련 데이터의 품질, 수량, 맥락적 의미에 따라 달라집니다. 이는 딥 러닝 모델을 구축할 때 가장 일반적인 과제 중 하나이며 비용과 시간이 많이 소요될 수 있습니다. 기업에서는 데이터 증강을 사용하여 훈련 사례에 대한 의존도를 줄여 고정밀 모델을 신속하게 구축합니다.

데이터 증대란 기존 데이터에서 새로운 데이터 포인트를 생성하여 데이터 양을 인위적으로 늘리는 것을 의미합니다. 여기에는 데이터에 사소한 변경 사항을 추가하거나 기계 학습 모델을 사용하여 원본 데이터의 잠재 공간에 새로운 데이터 포인트를 생성하여 데이터 세트를 증폭시키는 것이 포함됩니다.

합성은 실제 이미지를 사용하지 않고 인위적으로 생성된 데이터를 표현하며 Generative Adversarial Networks에서 제작합니다.

증강은 훈련 세트의 다양성을 높이기 위해 약간의 기하학적 변형(예: 뒤집기, 평행 이동, 회전 또는 노이즈 추가)이 포함된 원본 이미지에서 파생됩니다.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

데이터 확대는 더욱 다양한 데이터 세트를 통해 ML 모델의 성능을 향상시키고 데이터 수집과 관련된 운영 비용을 절감합니다.

  • 왼쪽-오른쪽 뒤집기: 이미지가 0.7의 확률로 무작위로 가로로 뒤집힙니다. 이는 이미지 속 피사체의 다양한 방향으로 인한 변화를 시뮬레이션합니다.
  • 회전: 이미지가 0.7의 확률로 약간(양방향으로 최대 10도) 회전됩니다. 이는 다양한 머리 자세를 시뮬레이션하여 데이터 세트에 가변성을 추가합니다.
  • 그레이스케일 변환: 0.1의 확률로 이미지가 그레이스케일로 변환됩니다. 이를 통해 모델은 색상 정보에 관계없이 이미지를 처리하고 학습할 수 있습니다.
  • 샘플링: Sample(50) 메서드는 원본 세트에서 50개의 증강 이미지를 생성합니다. 이렇게 하면 데이터세트가 확장되어 모델이 학습할 수 있는 더 많은 데이터가 제공됩니다.

VGG16 모델 구현

VGG16은 이미지 인식에 널리 사용되는 컨볼루셔널 신경망입니다. 최고의 컴퓨터 비전 모델 아키텍처 중 하나로 간주됩니다. 정확도를 높이기 위해 이미지를 점진적으로 처리하는 16개 층의 인공 뉴런으로 구성됩니다. VGG16에서 "VGG"는 옥스퍼드 대학교의 시각적 기하학 그룹을 의미하고, "16"은 네트워크의 16개 가중치 레이어

를 의미합니다.

VGG16은 이미지 인식 및 새로운 이미지 분류에 사용됩니다. VGG16 네트워크의 사전 훈련된 버전은 ImageNet 시각적 데이터베이스의 백만 개가 넘는 이미지에 대해 훈련되었습니다. VGG16을 적용하면 이미지에 특정 항목, 동물, 식물 등이 포함되어 있는지 확인할 수 있습니다.

VGG16 아키텍처

Using VGGfor face and gender recognition

13개의 컨벌루션 레이어, 5개의 Max Pooling 레이어, 3개의 Dense 레이어가 있습니다. 결과적으로 16개의 가중치를 갖는 21개의 레이어가 생성됩니다. 즉, 학습 가능한 매개변수 레이어가 16개라는 의미입니다. VGG16은 입력 텐서 크기를 224x244로 사용합니다. 모델은 스트라이드 1의 3x3 필터 컨볼루션 레이어를 갖는 데 중점을 둡니다. 항상 스트라이드 2의 2x2 필터의 맥스풀 레이어와 동일한 패딩을 사용합니다.

Conv-1 레이어에는 64개의 필터가 있고, Conv-2에는 128개의 필터가 있고, Conv-3에는 256개의 필터가 있고, Conv 4와 Conv 5에는 512개의 필터가 있으며, 처음 두 레이어에는 각각 4096개의 채널이 있고 세 번째 레이어에는 완전히 연결된 레이어 3개가 있습니다. 1000방향 ILSVRC 분류를 수행하고 1000개의 채널(각 클래스당 하나씩)을 포함합니다. 마지막 레이어는 소프트맥스 레이어입니다.

베이스 모델 준비를 시작합니다.

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

모델이 이미지를 올바르게 분류하는지 확인하려면 추가 레이어로 모델을 확장해야 합니다.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

Global Average Pooling 2D 레이어는 VGG16에서 얻은 특징 맵을 맵당 단일 1D 벡터로 압축합니다. 출력을 단순화하고 전체 매개변수 수를 줄여 과적합 방지에 도움이 됩니다.

밀집 레이어는 추가된 완전 연결(밀집) 레이어의 시퀀스입니다. 각 레이어에는 일반적인 관행과 실험을 기반으로 선택된 지정된 수의 장치(1024, 512 및 256)가 포함되어 있습니다. 이 레이어는 VGG16에서 추출한 기능을 추가로 처리합니다.

최종 Dense 계층(출력 계층)은 이진 분류에 적합한 시그모이드 활성화를 사용합니다(두 클래스는 '여성'과 '남성'임).

아담 최적화

Adam 최적화 알고리즘은 훈련 데이터를 기반으로 반복적으로 네트워크 가중치를 업데이트하는 확률적 경사하강법 절차를 확장한 것입니다. 이 방법은 많은 데이터나 매개변수가 포함된 대규모 문제를 처리할 때 효율적입니다. 메모리가 덜 필요하고 효율적입니다.

이 알고리즘은 모멘텀과 RMSP(Root Mean Square Propagation)라는 두 가지 경사하강법을 결합합니다.

모멘텀은 경사도의 지수가중평균을 사용하여 경사하강법 알고리즘을 가속화하는 데 사용되는 알고리즘입니다.

Using VGGfor face and gender recognition

Root Mean Square Prop은 "지수 이동 평균"을 취하여 AdaGrad를 개선하려는 적응형 학습 알고리즘입니다.

Using VGGfor face and gender recognition

mt와 vt는 모두 0으로 초기화되었기 때문에(위 방법에 따라) β1 & β2 ≒ 1이므로 '0을 향해 편향'되는 경향이 있는 것으로 관찰됩니다. 이 최적화 프로그램은 다음을 계산하여 이 문제를 해결합니다. '바이어스 수정' mt 및 vt. 이는 또한 전역 최소값에 도달하면서 가중치를 제어하여 근처에 있을 때 높은 진동을 방지하기 위해 수행됩니다. 사용된 공식은 다음과 같습니다.

Using VGGfor face and gender recognition

직관적으로 우리는 매 반복마다 경사하강법에 적응하여 프로세스 전반에 걸쳐 제어되고 편향되지 않은 상태를 유지하므로 Adam이라는 이름이 붙었습니다.

이제 일반 가중치 매개변수 mt 및 vt 대신 편향 보정된 가중치 매개변수 (m_hat)t 및 (v_hat)t를 사용합니다. 이를 일반 방정식에 대입하면 다음과 같은 결과를 얻습니다.

Using VGGfor face and gender recognition

출처: Geeksforgeeks, https://www.geeksforgeeks.org/adam-optimizer/

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

딥 러닝 맥락에서 이미지 데이터 전처리, 증강 및 모델 훈련을 설정합니다.

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontal_face_default.xml")) # haar cascade detects faces in images

vgg_face_dataset_url = "http://www.robots.ox.ac.uk/~vgg/data/vgg_face/vgg_face_dataset.tar.gz"

with request.urlopen(vgg_face_dataset_url) as r, open(os.path.join(base_path, "vgg_face_dataset.tar.gz"), 'wb') as f:
  f.write(r.read())

# extract VGG dataset
with tarfile.open(os.path.join(base_path, "vgg_face_dataset.tar.gz")) as f:
  f.extractall(os.path.join(base_path))

# download Haar Cascade for face detection
trained_haarcascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
with request.urlopen(trained_haarcascade_url) as r, open(os.path.join(base_path, "haarcascade_frontalface_default.xml"), 'wb') as f:
    f.write(r.read())
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
  • 에포크: 에포크 수는 전체 훈련 데이터 세트가 신경망을 통해 앞뒤로 전달되는 양을 지정합니다. 모델은 훈련 데이터를 10번 거치게 됩니다. 에포크는 학습 기계에 학습될 데이터 세트의 완전한 프레젠테이션입니다.
  • batch_size: 이 매개변수는 한 번에 네트워크를 통해 전파되는 샘플 수를 정의합니다. 여기서는 배치 크기 30을 사용합니다. 즉, 모델이 한 번에 30개의 이미지를 가져와 처리하고 가중치를 업데이트한 후 30개 이미지의 다음 배치로 진행한다는 의미입니다.

모델의 성능은 검증 세트에 대한 예측을 통해 평가됩니다. 이는 모델이 보이지 않는 데이터를 얼마나 잘 수행하는지에 대한 아이디어를 제공합니다. 각 이미지를 두 클래스("남성" 또는 "여성") 중 하나로 분류하기 위해 이러한 예측에 임계값이 적용됩니다.

# populate the list with the files of the celebrities that will be used for face recognition
all_subjects = [subject for subject in sorted(os.listdir(os.path.join(base_path, "vgg_face_dataset", "files"))) if subject.startswith("Jesse_Eisenberg") or subject.startswith("Sarah_Hyland") or subject.startswith("Michael_Cera") or subject.startswith("Mila_Kunis") and subject.endswith(".txt")]

# define number of subjects and how many pictures to extract
nb_subjects = 4
nb_images_per_subject = 40
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

정확도를 시각화하기 위해 혼동 행렬을 만듭니다.

images = []

for subject in all_subjects[:nb_subjects]:
  with open(os.path.join(base_path, "vgg_face_dataset", "files", subject), 'r') as f:
    lines = f.readlines()

  images_ = []
  for line in lines:
    url = line[line.find("http://"): line.find(".jpg") + 4]

    try:
      res = request.urlopen(url)
      img = np.asarray(bytearray(res.read()), dtype="uint8")
      # convert the image data into a format suitable for OpenCV
      # images are colored 
      img = cv2.imdecode(img, cv2.IMREAD_COLOR)
      h, w = img.shape[:2]
      images_.append(img)
      cv2_imshow(cv2.resize(img, (w // 5, h // 5)))

    except:
      pass

    # check if the required number of images has been reached
    if len(images_) == nb_images_per_subject:
      # add the list of images to the main images list and move to the next subject
      images.append(images_)
      break
로그인 후 복사
로그인 후 복사

이진 분류의 경우 ROC(수신기 작동 특성) 곡선과 AUC(곡선 아래 면적)는 참양성률과 거짓양성률 간의 균형을 이해하는 데 유용합니다.

# create arrays for all 4 celebrities
jesse_images = []
michael_images = []
mila_images = []
sarah_images = []

faceCascade = cv2.CascadeClassifier(os.path.join(base_path, "haarcascade_frontalface_default.xml"))

# iterate over the subjects
for subject, images_ in zip(all_subjects, images):

  # create a grayscale copy to simplify the image and reduce computation
  for img in images_:
    img_ = img.copy()
    img_gray = cv2.cvtColor(img_, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(
        img_gray,
        scaleFactor=1.2,
        minNeighbors=5,
        minSize=(30, 30),
        flags=cv2.CASCADE_SCALE_IMAGE
    )
    print("Found {} face(s)!".format(len(faces)))

    for (x, y, w, h) in faces:
        cv2.rectangle(img_, (x, y), (x+w, y+h), (0, 255, 0), 10)

    h, w = img_.shape[:2]
    resized_img = cv2.resize(img_, (224, 224))
    cv2_imshow(resized_img)

    if "Jesse_Eisenberg" in subject:
        jesse_images.append(resized_img)
    elif "Michael_Cera" in subject:
        michael_images.append(resized_img)
    elif "Mila_Kunis" in subject:
        mila_images.append(resized_img)
    elif "Sarah_Hyland" in subject:
        sarah_images.append(resized_img)
로그인 후 복사
로그인 후 복사

결론

결론적으로 딥러닝과 이미지 처리 알고리즘을 사용하면 사람의 얼굴을 인식하고 이를 남성 또는 여성으로 분류하는 Python 프로젝트를 구축할 수 있습니다.

위 내용은 얼굴 및 성별 인식에 VGG 사용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!