- 리눅스 배포판 확인

$ cat  /etc/*release

 

- 리눅스 커널버전 확인

$ cat /proc/version

$ uname -r

 

- CPU 정보

$ cat /proc/cpuinfo

     $ cat /proc/cpuinfo | more

     $ cat /proc/cpuinfo | grep name

$ nproc : 코어수

 

- 메모리정보

$ free

$ cat /proc/meminfo

 

- 하드디스크 정보

$ df -h (논리 디스크 파티션)

$ fdisk -l (물리 디스크)

$ hdparm (시리얼넘버 포함한 디스크 상세정보) <= sudo apt install hdparm

 

- 메인보드 정보

$ dmidecode : 메인보드 DMI 테이블 정보 출력

     $ sudo dmidecode -s baseboard-manufacturer : 메인보드 제조사

     $ sudo dmidecode -s baseboard-product-name : 제품명

     $ sudo dmidecode -s bios-vendor : 바이오스 공급사

     $ sudo dmidecode -s bios-version : 바이오스 버전

     $ sudo dmidecode -s bios-release-date : 바이오스 출시일

     $ sudo dmidecode -t processor | more : cpu

     $ sudo dmidecode -t memory | more : memory

     등등

 

- 기타

$ lshw : CPU, 메모리, 메인보드, 바이오스 등등

     $ lshw -html > Hardware.html (웹브라우저로 열어서 보면된다.)

 

$ lspci : 메인보드, VGA, Sound, PCI 등등

     $ lspci | grep VGA 

     $ lspci | grep USB

     $ lspci | grep SATA

     $ lspci | grep PCI

     등등

 

$ cat /proc/devices : 캐릭터 디바이스, 블록디바이스 확인가능

5년된 MSI PE60-6QE 노트북을 딥러닝용으로 사용하기 위해 Ubuntu 18.04-LTS를 설치했습니다.

 

1. Ubuntu18.04 LTS 설치 USB 만들기

 

해당 링크에서 ubuntu-18.04.4-desktop-amd64.iso를 다운받습니다.

https://releases.ubuntu.com/18.04/

 

저는 rufus 프로그램으로 우분투 설치 USB를 구웠습니다. (링크: https://rufus.ie/)

Secure Boot 모드면 MBR 형식으로

UEFI 모드면 GPT 형식으로 구워주면 됩니다.

만약에 UEFI에 듀얼부팅인데 윈도우가 MBR이면 GPT가 아닌 MBR로 해야한다고 합니다.

현재 부트모드를 모르겠다면 바이오스 진입해서 확인하고 원하는 설정으로 바꿔야 합니다.

 

제 MSI 노트북 기준이라 메인보드 회사나나 펌웨어 버전에 조금씩 다를 수 있습니다.

부팅화면에서 Del를 눌러 바이오스 화면으로 진입합니다.

Boot 메뉴에 진입하면 Boot mode select에 UEFI with CSM/Legacy/UEFI 세 가지 모드가 있는데 원하시는 모드로 선택하면 됩니다.

Security 메뉴에서 Secure Boot menu에 들어가면 Secure Boot 항목이 있습니다.

UEFI 모드면 Disabled, Legacy 모드면 Enabled 로 설정해 줍니다.

설정을 다했다면 저장하고 바이오스를 나옵니다.

 

노트북에 USB 꽂고 부팅을 해줍니다. 제경우에 usb3.0포트에서는 인식이 안되고, usb2.0에서만 인식했습니다.

F11을 눌러 USB를 선택해주고 설치를 시작합니다.

 

2. Ubuntu18.04 LTS 설치

 

GRUB 화면이 뜨면 Install Ubuntu를 선택해 줍니다.

언어는 영어로 하고 키보드는 한글로 선택했습니다.

Normal Installation 선택하고, 업데이트와 써드파티 드라이버 옵션은 상황에 맞게 선택해서 하시면 됩니다.

저는 우분투 단독으로 사용하는거라 디스크 다 지우고 설치하지만, 듀얼하시는 경우 LVM 설정해주셔야 합니다.

시간대 서울 선택하고, 로그인 계정 설정해주면 됩니다.

저 같은 경우는 편의성을 위해 자동 로그인으로 해두었습니다.

 

3. Ubuntu18.04 LTS 기본환경설정 (데스크탑 기준)

- 루트설정

 

$ sudo passwd root

Enter new UNIX password:

Retype new UNIX password:

 

- sudoer 계정추가

 

$ sudo chmod u+w /etc/sudoers

$ sudo vi /etc/sudoers

root ALL=(ALL:ALL) ALL
user ALL=(ALL:ALL) ALL

root 밑에 유저계정 추가 저장 후 종료.

 

- 네트워크 고정IP

 

 

- SSH

 

$ sudo apt-get install ssh

$ sudo systemctl enable ssh

$ sudo systemctl start ssh

$ sudo systemctl status ssh

 

 

- Samba

 

$ sudo apt-get install samba

$ sudo apt-get install system-config-samba

$ sudo touch /etc/libuser.conf (해당파일 생성해야 system-config-samba 실행됨)

$ mkdir workspace

$ sudo system-config-samba

Preferences에서 삼바 유저추가

+ 버튼 눌러서 삼바디렉토리 추가 및 설정

Access 에서 삼바유저 체크

system-config-samba 종료

 

$ sudo systmectl restart smbd

$ sudo systemctl status smbd

 

- 방화벽

 

$ sudo apt-get install firewall-config

$ sudo firewall-cmd --add-service=ssh --permanent

$ sudo firewall-cmd --add-service=samba --permanent

$ sudo firewall-cmd --reload

 

- 패키지 서버 다음카카오로 변경 (선택사항)

 

$ sudo cp /etc/apt/sources.list /etc/apt/sources.list.org

$ sudo vi /etc/apt/sourece/list

     다음 명령어로  서버변경

     :%s/kr.archive.ubuntu.com/ftp.daumkakao.com

     or :%s/us.archive.ubuntu.com/ftp.daumkakao.com

     저장하고 종료 :wq

 

- 업데이트

 

$ sudo apt-get update

 

- 업그레이드

 

$ sudo apt-get upgrade

 

 

4. 우분투 Synergy 설치

보통 윈도우 데스크탑과 같이 작업하기 때문에

작업 편의성을 위해 사용하는 키보드 마우스 공유 프로그램입니다.

https://sourceforge.net/projects/synergy-stable-builds/files/v1.8.8-stable/

해당링크에서 다운받아서 설치해서 윈도우 데스크탑을 서버로 사용하고 있습니다.

와이파이는 끊기거나 딜레이 생기는 경우가 있어서 유선랜 사용을 추천드립니다.

 

$ sudo apt-get install synergy

설치가 완료되면 Show Applications에서 Synergy를 찾아서 실행시킵니다.

실행이 좀 오래 걸립니다. 15초 정도 기다리면 경고창 뜨는데 OK 누릅니다.

 

Edit->Settings 에서 Screen Name을 설정합니다. 서버에서 설정하는 클라이언트 이름하고 똑같아야 합니다.

그리고 무료인 경우 Use SSL encrytrion 을 해제시켜줍니다.

그리고 메인화면에서 Auto config를 해제하고, 서버의 IP 주소를 적어주고 Start를 눌러서 시작합니다.

시작하고 나선 Synergy 윈도우창 종료해도 됩니다.

 

매번 이렇게 설정하기 귀찮으니 시작프로그램에 추가합니다.

Show Applications에서 Startup Applications를 실행합니다.

커맨드 입력창

     => /usr/bin/synergyc --daemon --debug DEBUG --name UBUNTU-LAPTOP 192.168.0.130:24800

     => /usr/bin/synergyc --daemon --debug DEBUG --name [Screen Name] [Server IP]:[Port]

 

 

 

============================================================================

 

사용하다보니 커널메세지에서 같은 에러가 지속적으로 발생하더군요.

PCIe Bus Error: serverity=Corrected, type=Physical Layer, id=00e0(Receiver ID)

찾아보니까 저전력 전환할때 이러한 오류가 생길수 있다고 합니다.

PCIe Active State Power Management를 끄면 일단 해결은 되는것 같습니다.

다음과 같이 pcie_aspm=off 를 추가해줍니다.

 

$ sudo gedit /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash pcie_aspm=off"

$ sudo update-grub

$ reboot

 

이렇게 하면 일단 에러 메세지 뜨는건 사라집니다.

pci=noaer 이나 pci=nomsi 알려주는 경우도 있는데 마찬가지로 에러메세지 없어지긴 합니다.

하지만 aspm 끄는게 내용적으로 더 근본적인 해결책 같습니다.

 

원래 Windows에서 그냥 작업하려고 했는데 나중에 해야하는 작업의 에뮬이 윈도우 지원을 안해서

할 수 없이, 우분투에 다시 설치 하게되었습니다.

 

1. 기존 Nvidia Driver 제거 및 Nouveau 드라이버 off

GPU 드라이버를 먼저 설치해야 하는데

CUDA에 Nvidia Driver가 포함되어 있으므로 Nvidia Driver을 따로 설치할 필요는 없습니다.

처음에 모르고 Nvidia Driver 설치하고, CUDA 설치하려는데  버전 충돌로  계속 실패해서 보니까

Nvidia Driver 설치하면 CUDA가 일부 설치되고, CUDA설치하면 Nvidia Driver가 설치되더군요.

그래서 결론적으로 CUDA만 설치하면 만사형통입니다.

 

기존에 설치된 드라이버가 있따면 새로 설치하는 CUDA와 충돌할 수 있으므로 설치전에 제거해줍니다.

$ sudo apt --purge autoremove "cublas*" "cuda*"

$ sudo apt --purge autoremove "nvidia*"

 

기타 Depedency를 설치합니다.

$ sudo apt-get install dkms build-essential linux-headers-generic

 

Nouveau를 off 설정해줍니다.

blacklist.conf에 아래 내용을 추가해줍니다.

$ sudo vi /etc/modprobe.d/blacklist.conf

blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias noveau off
alias lbm-nouveau off

$ echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf

$ sudo update-initramfs -u

$ sudo reboot

 

2. CUDA 10.0 설치

 

CUDA 10.0 archive => https://developer.nvidia.com/cuda-10.0-download-archive

다음과 같이 환경에 맞는 버전을 선택합니다.

다운로드를 눌러 파일을 다운받고, 설명되어 있는대로 명령어를 입력합니다.

그리고 경로설정을 해줍니다.

$ sudo gedit ~/.bashrc (맨 밑에 추가)

export PATH=/usr/local/cuda-10.0/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

$ sudo apt autoremove

$ source ~/.bashrc

$ reboot

 

설치확인

$nvidia-smi

$nvcc -V

 

3. CuDNN7 설치

 

CuDNN Archive => https://developer.nvidia.com/rdp/cudnn-archive

 

CUDA 10.0 지원하는 버전 설치

저는 7.6.5로 다운받아 설치했습니다.

로그인 해야 다운로드 받을 수 있는데 가입이 안되어 있다면 가입하시면 됩니다.

단순히 실행 목적이라면 Rutime만 받으면 됩니다 nvidia 샘플까지 돌린다면 Developer 로 다운 받습니다.

Runtime만 받아도 사용하는데는 문제없습니다.

다운로드 완료되면 설치를 시작합니다.

Runtime Library : $ sudo dpkg -i libcudnn7_7.6.5.32-1+cuda10.0_amd64.deb

Developer Library : $ sudo dpkg -i libcudnn7-dev_7.6.5.32-1+cuda10.0_amd64.deb

더보기

Developer 설치 시 libcudnn7 관련 에러메세지 뜨는 경우

$ sudo apt --fix-broken install

Runtime 먼저 설치하고, Developer 설치하면 에러 없이 설치완료 됩니다.

 

$ sudo apt update

$ sudo apt install -y libcudnn7 libcudnn7-dev libc-ares-dev

 

$ sudo apt autoremove

$ sudo apt upgrade

 

$ sudo ln -s /usr/lib/x86_64-linux-gnu/libcudnn.so.7 /usr/local/cuda-10.0/lib64/

$ reboot

 

설치 확인

$ sudo find / -name "cudnn.h"

/usr 밑에 있는 cudnn.h 경로 확인

$ cat /usr/include/cudnn.h | grep CUDNN_MAJOR -A 2

 

4. Caffe 다운 및 빌드

 

- OpenCV

$ sudo apt install python3-opencv

 

- OpenBLAS
$ sudo apt-get install libopenblas-dev # OpenBLAS

 

- Other Dependencies

$ sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler

$ sudo apt-get install --no-install-recommends libboost-all-dev

$ sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev

$ sudo apt-get install the python3-pip python3-dev

 

- Caffe 다운로드

$ sudo git clone https://github.com/BVLC/caffe.git 

$ cd caffe

$ cp Makefile.confg.example Makefile.config

$ gedit Makefile.config

<수정내용>
OPENCV_VERSION := 3

# -gencode arch=compute_20,code=sm_20 \
# -gencode arch=compute_20,code=sm_21 \

BLAS := open # if you’ve installed OpenBLAS

# PYTHON_INCLUDE := /usr/include/python2.7 \
# /usr/lib/python2.7/dist-packages/numpy/core/include

INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib/x86_64-linux-gnu/hdf5/serial

PYTHON_LIBRARIES := boost_python3 python3.6m
PYTHON_INCLUDE := /usr/include/python3.6m \
		/usr/lib/python3.6/dist-packages/numpy/core/include

$ sudo make clean

 

$ sudo make -j 6

$ sudo make test -j 6

$ sudo make runtest

 

빌드가 에러없이 모두 실행된다면 Caffe 프레임워크 구축이 완료된겁니다.

추가로 편의성을 위해 CAFFE_ROOT 경로를 지정해줍니다.

 

$ sudo gedit ~/.bashrc (맨 밑에 추가)

export CAFFE_ROOT=/home/user/workspace/caffe

$ source ~/.bashrc

$ cd $CAFFE_ROOT

 

 

 

 

 

레퍼런스

gist.github.com/bogdan-kulynych/f64eb148eeef9696c70d485a76e42c3a

medium.com/@anidh.singh/install-caffe-on-ubuntu-with-cuda-6d0da9e8f860

'딥러닝' 카테고리의 다른 글

[딥러닝] Windows 10에서 Caffe 프레임워크 구축  (0) 2020.08.04

※ SD카드와 SD카드 USB인식기 필요

 

1. 해당 링크에서 우분투 이미지를 다운받습니다.

=> https://ubuntu.com/download/raspberry-pi

 

2. SD카드에 이미지를 굽습니다.

 

라이터 프로그램 둘 중 하나 설치하시면 됩니다.

Win32DiskImager - https://sourceforge.net/projects/win32diskimager/

Balena Etcher - https://www.balena.io/etcher/

 

설치한 프로그램에서 다운받은 이미지와 SD카드를 선택해서 이미지를 구워줍니다.

(※ Win32DiskImager은 굽기 전에 압축해체 해야합니다.)

 

3. SD카드를 라즈베리파이4에 장착하고 부팅해줍니다.

처음에 부팅하면 계정 및 비밀번호 모두 ubuntu 입니다. 

입력해서 로그인 하면 비번 새로 바꾸라고 합니다.

기존 비밀번호 입력하고, 새 비밀번호 2번 입력하면 됩니다.

 

그리고 root 비번 먼저 설정해 줍니다.

$sudo passwd root

비밀먼호 입력해 줍니다.

 

4. 환경설정 

- 네트워크 고정IP

 

먼저 네트워크 이름부터 확인합니다.

$ ifconfig

저는 eth0 이었습니다.

다음 디렉토리로 이동해서 파일을 확인합니다.

$ cd /etc/netplan

$ ls

저는 50-cloud-init.yaml 이었습니다. 정확지는 않은데 이름이 다를수도 있는거 같습니다.

수정 전에 원본을 복사합니다.

$ sudo cp 50-clould-init.yaml 50-clould-inti.yaml.org

파일을 수정합니다.

$ sudo vi 50-cloud-init.yaml

	network:
		ethernets:
			eth0:
				# dhcp4: true
                # optional : true
				addresses:[192.168.0.70/24]
				gateway4: 192.168.0.1
				nameservers:
					addresses: [8.8.8.8, 8.8.4.4]
		version: 2

수정한 내용을 적용합니다.

$ sudo netplan apply

적용된 IP주소를 확인 합니다.

$ hostname -I 

 

- SSH 설치

 

$ sudo apt-get install ssh

$ sudo systemctl enable ssh

$ sudo systemctl start ssh

$ sudo systemctl status ssh

 

- Samba 설치

 

$ sudo apt-get install samba

공유폴더 생성

$ mkdir workspace

삼바계정 추가

$ sudo smbpasswd -a ubuntu

smb.conf 맨 밑에 추가

$ sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.org

$ sudo vi /etc/samba/smb.conf

[ubuntu]

    comment = samba directory
    path = home/ubuntu/workspace
    valid users = ubuntu
    writeable = yes
    read only = no
    create mode = 0777
    directory mode = 0777

$ sudo systemctl restart smbd

$ sudo systemctl status smbd

 

- 방화벽 설치 및 설정

 

$ sudo apt-get install firewall-config

$ sudo firewall-cmd --add-service=ssh --permanent

$ sudo firewall-cmd --add-service=samba --permanent

$ sudo firewall-cmd --reload

 

- 외장하드 마운트

 

외장하드 경로 확인

$ sudo fdisk -l

용량 같은 걸로 어떤게 외장하드인지 확인가능하며 마운트 전이라 $ df 에서는 안뜹니다.

제 경우엔 /dev/sda1 이었습니다.

 

디스크 파티션

$ sudo fdisk /dev/sda1

Command (m for help): n
Select (default p): p
Partition number (1-4, default 1): 1
First sector 생략~~~ : 엔터
Last sector 생략~~~ : 엔터

Command (m for help): p

Command (m for help): w

디스크 포맷

$ sudo mkfs.ext4 /dev/sda1

 

자동 마운트 설정 및 마운트

$ sudo blkid => "UUID 확인"

디렉토리 생성하거나 기존 디렉토리 사용

$ sudo vi /etc/fstab 

UUID=생략 /home/ubunut/workspace ext4 defaults 0 0

마운트 적용

$ sudo mount -a

확인

$ df -h

 

- vsftpd 설치 및 적용

 

설치 및 재시작

$ sudo apt-get install vsftpd

$ sudo service vsftpd restart

 

계정추가

$ sudo adduser ubuntu

 

vsftpd.conf 수정

$ sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.org

$ sudo vi /etc/vsftpd.conf (※ 내용 다 지우고 아래내용만 복사해서 입력하거나, 찾아서 수정하거나 추가하시면 됩니다.)

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
pasv_enable=YES
pasv_min_port=10000
pasv_max_port=11000
user_sub_token=$USER
local_root=/home/ubuntu/workspace

userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO

유저리스트 생성

$ sudo vi /etc/vsftpd.userlist

ubuntu

vsftpd 재시작

$ sudo service restart vsftpd

 

파일질라 같은 프로그램으로 외부에서 ftp 접속해서 확인해 봅니다.

 

- 데스크탑 GUI설치

 

$ sudo apt-get install ubuntu-desktop

제일 오래 걸리는 작업이므로 마지막에 하는게 저는 편하더군요.

1. Visual Studio 2015 설치

       해당 버전으로 다운로드 받아 설치합니다 => Visual Studio Community 2015 with Update 3 

       설치 시에 Windows 8.1 SDK도 선택해서 설치해 줍니다.

       만약에 해당 패키지가 설치되어 있지 않았다면 프로젝트 생성 대화상자에서 

       Visual C++ 카테고리로 이동해서 다음 메뉴를 선택해서 설치해 줍니다.

       해당 메뉴가 없고, 프로젝트 목록들이 뜬다면 이미 설치되어 있는 겁니다.

 

2. Python 3.5 설치 ( ※ 2.7 이나 3.5 둘중 하나 선택해서 설치해야 합니다. )

       https://www.python.org/downloads/windows/

       저는 3.5.0에서 Windows x86-64 executable installer로 다운받아서 설치 했습니다.

       기본경로가 복잡해서 경로를 변경해서 설치했습니다.

 

       설치가 끝나면 확장 패키지를 다운받습니다.

        https://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy

       저는 3.5에서 최신인 numpy‑1.16.6+vanilla‑cp35‑cp35m‑win_amd64.whl를 다운 받았습니다.

       다운받고 cmd 에서 다음 명령어를 순서대로 실행합니다.

             pip 버전 업그레이드

             > python -m pip install --upgrage pip

             numpy 패키지 설치

             > python -m pip install "D:\download\numpy‑1.16.6+vanilla‑cp35‑cp35m‑win_amd64.whl"

 

3. CMake 3.6 설치

       https://cmake.org/files/v3.6/

       다음과 같이 해당되는 파일 받아 설치하면 됩니다.  => cmake-3.6.0-rc1-win64-x64.msi

  

4. Git 설치

       https://git-scm.com/downloads

       윈도우용 최신버전 다운받으시면 됩니다.

       에디터는 편한걸로 선택하고, default 세팅으로 설치진행하면 됩니다.

 

5. Caffe 프레임워크 설치 및 빌드

       cmd에서 설치를 원하시는 폴더로 이동합니다.

            Git Clone

            > git clone https://github.com/BVLC/caffe.git

            Branch Switching

            > cd caffe

            > git checkout windows

 

       VS2015를 사용할 것이므로 caffe/scripts/build_win.cmd를 에디터로 열어서

       WITH_NINJA를 찾아서 모두 0으로 바꿔줍니다.

       cmd로 돌아와 빌드를 실행합니다.

            Build Caffe

            > cd scripts

            > build_win.cmd

       

      아무 문제 없다면 몇 분간 빌드를 계속 실행합니다.

      이상 없이 마무리 되면 다음과 같이 끝이 납니다.

      버전만 틀리게 설치하지 않았다면 문제없이 빌드 될겁니다.

      CPU버전은 설정이 끝났습니다.

      그래픽카드로 연산하시려면 계속해서 CUDA와 cuDNN으로 설치해주면 됩니다.

 

6. CUDA8.0 설치

      https://developer.nvidia.com/cuda-80-ga2-download-archive

      OS에 맞춰서 다운로드 받아서 설치해주면 됩니다.

      다운받은 파일을 실행시켜 설치를 진행합니다.

      이것도 설치경로 단순하게 변경했습니다.

      제 경우엔 설치완료단계에서 디스플레이 설정인지 패치하는 과정에서 화면이 꺼졌습니다.

      혹시나해서 몇 분 기다렸는데  화면이 나오질 않아 재부팅했습니다.

      설치완료인지 확신이 가지않아 검색해서 몇 가지 확인해보았습니다.

      cmd를 실행해서 다음 명령어를 입력합니다.

      > nvcc -V

      버전확인은 문제 없는것 같습니다.

      확실하게 하기위해 샘플하나 컴파일해서 실행되는지 확인했습니다.

      C:\CUDA\CUDASamples\0_Simple\asyncAPI 로 이동해서 asyncAPI_vs2015.sln을 실행시켜 컴파일했습니다.

      정의안된거라고 빨갛게 표시되는 변수가 몇개 있었는데 컴파일 하는데 문제는 없었습니다.

      바로 실행시켜도 되고, 응용프로그램은 C:\CUDA\CUDASamples\bin\win64\Debug에 생성됩니다.

      문제없으면 비슷하게 출력될 겁니다.

 

      패치는 설치안해도 크게 상관없는거 같은데 제 경우에는 패치도 설치했습니다.

      기존에 설치된 CUDA가 없다면 신경안써도 되는데, 다른버전이 중복설치되거나 설치했던적 있다면

      시스템 환경변수에 CUDA_PATH의 경로이름 버전이 제대로 설정되어있는지 확인하는 것이 좋습니다.

 

7. cuDNN 5.0 설치

      https://developer.nvidia.com/rdp/cudnn-archive

      링크에서 CUDA 8.0에 호환하는 cuDNN을 다운받으면 됩니다.

      저는 cuDNN v5를 다운 받았습니다.

      다운받아서 원하시는 경로에 압축을 푸시면 됩니다.

      그리고 아까 수정했던 caffe\scripts\build_win.cmd를 다시 수정합니다.

      빨간색으로 체크한 부분이 추가한 부분으로 cuDNN의 경로를 입력하시면 됩니다.

      그리고 아까와 같이 cmd 에서 build_win.cmd 스크립트를 실행시켜주면 됩니다.

           

      GPU버전 Caffe 빌드 까지 완료했습니다.

 

 

 

제가 보려고 간략하게 정리한겁니다.

다음 레퍼런스에서 자세한 내용 보실 수 있습니다.

=> https://baemincheon.tistory.com/21

 

'딥러닝' 카테고리의 다른 글

[딥러닝] 우분투 18.04 Caffe 프레임워크 구축  (0) 2020.08.10

https://cornbro.tistory.com/3에서 이어지는 내용입니다.

 

먼저 RTCPeerConnection은 비디오 및 오디오 데이터 교환을 위한 API입니다.

해당 예제는 실제 외부접속은 아니며 PeerConnection API 작동 방식을 이해하기위한 단순 로컬 예제입니다.

 

work/index.html에 다음과 같이 내용을 추가합니다.

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>
  
    <video id="localVideo" autoplay playsinline></video>
	<video id="remoteVideo" autoplay playsinline></video>
	
	<div>
		<button id="startButton">Start</button>
		<button id="callButton">Call</Button>
		<button id="hangupButton">Hang Up</button>
		<button id="stopButton">Stop</button>
	</div>	

  <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
  <script src="js/main.js"></script>

</body>

</html>

2개의 비디오 구성과 4개의 컨트롤 버튼을 추가하였습니다.

 "localVideo"는 getUserMedia()를 통해 비디오 스트림을 가져오고,  "remoteVideo"는 RTCPeerConnection통해 동일한 비디오 스트림을 가져옵니다.

 그리고 최신 버전의 adapter.js shim 링크를 연결해줍니다.

더보기

 adapter.js : 규격화를 통해 대부분의 프로토콜은 동일하게 구성되었지만 다른 브라우져간에 생기는 일부 다른 부분(ex. prefix)을 호환 시켜주기 위해 사용하게 됩니다.

step-2 폴더에 있는 main.js를 work 폴더로 옮겨서 열어봅니다.

개인적으로 로컬 스트림도 닫을수 있게 stop버튼을 추가했습니다.

 

변수 생성 및 상태 로그 메세지에 대한 내용은 넘어가도록 하겠습니다.

 

start 버튼에서 로컬 미디어 스트림을 가져옵니다. => gotLocalMediaStream()

// Handles start button action: creates local MediaStream.
function startAction() {
  startButton.disabled = true;
  navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
    .then(gotLocalMediaStream).catch(handleLocalMediaStreamError);
  trace('Requesting local stream.');
}

//--------------------------------------------------------------------------------
      // Sets the MediaStream as the video element src.
      function gotLocalMediaStream(mediaStream) {
        localVideo.srcObject = mediaStream;
        localStream = mediaStream;
        trace('Received local stream.');
        callButton.disabled = false;  // Enable call button.
        stopButton.disabled = false;
      }
//--------------------------------------------------------------------------------

call 버튼에서 Peer Connection을 통해 end to end 연결을 하고 => handleConnection()

로컬에서 원격으로 비디오 스트림을 가져옵니다. => gotRemoteMediaStream()

실제에서는 메시징 서비스를 통해 외부로 연결되겠지만, 해당 스텝에서는 같은 페이지에서 직접 통신을 합니다.

WebRTC Peer는 해상도 및 코덱 기능과 같은 미디어 정보를 교환해야 합니다.

SDP 프로토콜의 Offer<->Answer 를 통해 메타 데이터의 Blob을 교환합니다. => createdOffer/createdAnswer

// Handles call button action: creates peer connection.
function callAction() {
  callButton.disabled = true;
  hangupButton.disabled = false;

  trace('Starting call.');
  startTime = window.performance.now();

  // Get local media stream tracks.
  const videoTracks = localStream.getVideoTracks();
  const audioTracks = localStream.getAudioTracks();
  if (videoTracks.length > 0) {
    trace(`Using video device: ${videoTracks[0].label}.`);
  }
  if (audioTracks.length > 0) {
    trace(`Using audio device: ${audioTracks[0].label}.`);
  }

  const servers = null;  // Allows for RTC server configuration.

  // Create peer connections and add behavior.
  localPeerConnection = new RTCPeerConnection(servers);
  trace('Created local peer connection object localPeerConnection.');

  localPeerConnection.addEventListener('icecandidate', handleConnection);
  localPeerConnection.addEventListener(
    'iceconnectionstatechange', handleConnectionChange);
  //---------------------------------------------------------------------    
        // Connects with new peer candidate.
        function handleConnection(event) {
          const peerConnection = event.target;
          const iceCandidate = event.candidate;

          if (iceCandidate) {
            const newIceCandidate = new RTCIceCandidate(iceCandidate);
            const otherPeer = getOtherPeer(peerConnection);

            otherPeer.addIceCandidate(newIceCandidate)
                .then(() => {
                	handleConnectionSuccess(peerConnection);
                }).catch((error) => {
                	handleConnectionFailure(peerConnection, error);
                });

            trace(`${getPeerName(peerConnection)} ICE candidate:\n` +
            	`${event.candidate.candidate}.`);
            }
        }
        
        // Gets the "other" peer connection.
        function getOtherPeer(peerConnection) {
          return (peerConnection === localPeerConnection) ?
              remotePeerConnection : localPeerConnection;
        }
        
        // Logs changes to the connection state.
        function handleConnectionChange(event) {
            const peerConnection = event.target;
            console.log('ICE state change event: ', event);
            trace(`${getPeerName(peerConnection)} ICE state: ` +
                  `${peerConnection.iceConnectionState}.`);
        }
  //---------------------------------------------------------------------    

  remotePeerConnection = new RTCPeerConnection(servers);
  trace('Created remote peer connection object remotePeerConnection.');

  remotePeerConnection.addEventListener('icecandidate', handleConnection);
  remotePeerConnection.addEventListener(
    'iceconnectionstatechange', handleConnectionChange);
  remotePeerConnection.addEventListener('addstream', gotRemoteMediaStream);
  
  //--------------------------------------------------------------------- 
  		// Handles remote MediaStream success by adding it as the remoteVideo src.
        function gotRemoteMediaStream(event) {
          const mediaStream = event.stream;
          remoteVideo.srcObject = mediaStream;
          remoteStream = mediaStream;
          trace('Remote peer connection received remote stream.');
        }
  //--------------------------------------------------------------------- 
  
  // Add local stream to connection and create offer to connect.
  localPeerConnection.addStream(localStream);
  trace('Added local stream to localPeerConnection.');

  trace('localPeerConnection createOffer start.');
  localPeerConnection.createOffer(offerOptions)
    .then(createdOffer).catch(setSessionDescriptionError);
    
  //--------------------------------------------------------------------- 
        // Logs offer creation and sets peer connection session descriptions.
        function createdOffer(description) {
          trace(`Offer from localPeerConnection:\n${description.sdp}`);

          trace('localPeerConnection setLocalDescription start.');
          localPeerConnection.setLocalDescription(description)
            .then(() => {
              setLocalDescriptionSuccess(localPeerConnection);
            }).catch(setSessionDescriptionError);

          trace('remotePeerConnection setRemoteDescription start.');
          remotePeerConnection.setRemoteDescription(description)
            .then(() => {
              setRemoteDescriptionSuccess(remotePeerConnection);
            }).catch(setSessionDescriptionError);

          trace('remotePeerConnection createAnswer start.');
          remotePeerConnection.createAnswer()
              .then(createdAnswer)
              .catch(setSessionDescriptionError);
        }
        
        // Logs answer to offer creation and sets peer connection session descriptions.
        function createdAnswer(description) {
          trace(`Answer from remotePeerConnection:\n${description.sdp}.`);

          trace('remotePeerConnection setLocalDescription start.');
          remotePeerConnection.setLocalDescription(description)
            .then(() => {
              setLocalDescriptionSuccess(remotePeerConnection);
            }).catch(setSessionDescriptionError);

          trace('localPeerConnection setRemoteDescription start.');
          localPeerConnection.setRemoteDescription(description)
            .then(() => {
              setRemoteDescriptionSuccess(localPeerConnection);
            }).catch(setSessionDescriptionError);
        }
  //--------------------------------------------------------------------- 
}

hangup 버튼에서 Peer Connection 연결을 닫아줍니다.

// Handles hangup action: ends up call, closes connections and resets peers.
function hangupAction() {
  localPeerConnection.close();
  remotePeerConnection.close();
  localPeerConnection = null;
  remotePeerConnection = null;
  hangupButton.disabled = true;
  callButton.disabled = false;
  trace('Ending call.');
}

stop 버튼에서 로컬 스트림을 닫아줍니다.

function stopAction() {
	if (hangupButton.disabled == false){
		hangupAction();
	}
	startButton.disabled = false;
	callButton.disabled = true;
	stopButton.disabled = true;
	
	localStream.getTracks().forEach((track) => {
		track.stop();
	});
}

 


파일 다운받아서 실행하면 화면처럼 똑같이 실행됩니다.

step_2.zip
0.02MB

 

 

'WebRTC' 카테고리의 다른 글

[WebRTC] 웹캠 영상 단순출력 예제  (0) 2020.01.12
[WebRTC] 개념정리  (1) 2020.01.07

구글코드랩스에서 제공하는 WebRTC 예제입니다.

https://codelabs.developers.google.com/codelabs/webrtc-web/#0

 

 

다음 링크에서 소스코드를 다운받을 수 있습니다.

https://github.com/googlecodelabs/webrtc-web

그리고 크롬 브라우저에서 Web Server 앱을 설치합니다.

https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en

설치한 후, 주소창에서 chrome://apps로 이동해 Web Server 앱을 선택해서 실행해 줍니다.

 

chrome://apps

 

실행된 창에서 다음 같이 세팅해 줍니다.

폴더는 다운로드한 소스코드에서 work이라는 폴더로 지정해주면 됩니다.

Web Server App

Web Server URL(s) : http://127.0.0.1:8887 클릭해서 창을 띄우시면 다음과 같은 화면을 보실 수 있습니다.

현재는 기능이 구현되지 않아 보시는 바와 같이 텍스트만 출력하고 있습니다.

초기실행

work폴더에 보시면 아시겠지만 index.html, main.css, main.js, adapter.js 이상 4개의 파일로 구성되어져 있습니다.

먼저, 다음 파일들을 열어서 코드를 추가로 입력해 줍니다.

'F12' 누르고 브라우저 상에서 작업하셔도 되고, 저 같은 경우 노트패드에서 작업했습니다.

 

 

 

 * index.html

<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <video autoplay playsinline></video>

  <script src="js/main.js"></script>

</body>

</html>

 

 * main.js

'use strict';

// On this codelab, you will be streaming only video (video: true).
const mediaStreamConstraints = {
  video: true,
};

// Video element where stream will be placed.
const localVideo = document.querySelector('video');

// Local stream that will be reproduced on the video.
let localStream;

// Handles success by adding the MediaStream to the video element.
function gotLocalMediaStream(mediaStream) {
  localStream = mediaStream;
  localVideo.srcObject = mediaStream;
}

// Handles error by logging a message to the console with the error message.
function handleLocalMediaStreamError(error) {
  console.log('navigator.getUserMedia error: ', error);
}

// Initializes media stream.
navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
  .then(gotLocalMediaStream).catch(handleLocalMediaStreamError);
  

다 입력하고 저장한 후에 'F5'번 키를 눌러 리로드 합니다.

처음 한번은 브라우져에서 카메라 접근 퍼미션 메세지가 뜰겁니다. 

확인하면 MediaStream이 반환되며, 웹캠을 통해 영상이 출력되는걸 확인할 수 있습니다.

웹캠 출력화면

 

그리고 Ctrl+Shift+J 를 눌러 콘솔창에서 커맨드를 입력해서 결과를 확인해 봅니다.

localStream.getVideoTracks()
localStream.getVideoTracks()[0].stop()

 

그리고 main.css에서 다음과 같이 다양한 이미지 옵션을 추가하거나 수정할 수 있습니다.

body {
  font-family: sans-serif;
}

video {
  max-width: 100%;
  width: 720px;
}

video {
  filter: blur(4px) invert(1) opacity(0.5);
}

video {
   filter: hue-rotate(180deg) saturate(200%);
}

 

'WebRTC' 카테고리의 다른 글

[WebRTC] 로컬 PeerConnecton 비디오 스트림 출력  (0) 2020.01.20
[WebRTC] 개념정리  (1) 2020.01.07

 WebRTC에 흥미가 생겨서 공부해보려고 정리한 내용입니다.

 

 WebRTC는 심플한 API를 통해 웹 브라우저와 모바일 어플리케이션에 RTC(Real-Time Communication) 지원하는 오픈소스 프로젝트로 별도의 플러그인이나 프로그램 설치 P2P통신을 통해 웹 페이지 내에서 오디오와 비디오 통신이 가능하게 해준다. 웹 브라우저 기반의 통신 방식인 WebRTC는 구글이 오픈소스화한 프로젝트에서 시작되었고 국제 인터넷 표준화 기구 프로토콜 표준화 작업을, W3C가 API정의를 진행하였다. 라이선스는 BSD


* 지원 플랫폼

   - PC : MS Edge 12+ / Chrome 28+ / Firefox 22+ / Safari 11+ / Opera 18+ / Vivaldi 1.9+

   - Android : Chrome 28+ / Firefox 24+ / Opera Mobile 12+

   - Chrome OS

   - Firefox OS

   - BlackBerry 10

   - iOS : MobileSafari/WebKit(iOS 11+)

   - Tizen 3.0

 

 * 지원 코덱

   - 오디오 : PCMU(G.711u) / PCMA(G.711a) / Opus

   - 비디오 : VP8 / VP9 /H.264(AVC)

 

 * 주요기능

   - getUserMedia : 로컬 비디오와 오디오에 접근하여 미디어 데이터를 가져온다.

   - RTCPeerConnection : 피어간 오디오, 비디오 통신을 활성화한다. 신호처리, 코덱관리, P2P통신, 보안, 대역폭 관리 등을 수행한다.

   - RTCDataChannel : 피어간 양방향 임의 데이터 통신을 허용한다. 웹 소켓과 동일한 API를 사용하며 낮은 레이턴시를 보여준다.

   - getStats : 관리를 위한 통계 API이다.

 

* 아키텍쳐

WebRTC Architecture

 

 * 시그널링

Simple Signaling

신호는 2개의 엔드 포인트가 메타 데이터를 교환하여 통신을 조정할 수 있도록 한다. SDP(Session Description Protocol)의 Offer <-> Answer 기반으로 구성되어 있다.

 

Simple Signaling Sequence

 * NAT/Firewall Traversal

 보통 클라이언트는 사설 IP주소를 사용하는 내부 호스트인데 P2P로 연결요청하면 NAT/Firewall에서 막혀서 응답을 받을 수 없다.

 

   - ICE(Interactive Connectivity Establishment), RFC5245

  ICE는 연결에 사용할 수 있는 모든 가능한 IP 후보군(사설 IP, STUN이 돌려주는 공인 IP)들을 조사하고, Peer간 직접 연결을 맺을 수 있는지를 확인하는 기술이다. 연결 테스트를 위해 SDP(Session Description Protocol)을 사용하여 미디어 패킷을 흘려 보내며 연결 가능 여부를 테스트 한다.

 

   - TURN(Traversal Using Relays around NAT), RFC5766

 공인 IP간 연결을 테스트해보고 연결이 가능하면 WebRTC 클라이언트들은 P2P연결이 된 것이지만, 만약 연결이 실패한다면 인터넷 상의 중계 서버(Relay Server)를 사용해야 하는데, 이 서버가 TURN 서버이다.

릴레이 주소를 할당하고 패킷 릴레이를 통해 상호연결한다.

   - STUN(Session Traversal Utilities for NAT), RFC3489

 WebRTC의 P2P 연결을 위해 NAT 뒷 단의 클라이언트들은 사설 IP를 내부에서 보유하고 있다. 외부 통신을 위해 자신의 공인 IP정보를 스스로 파악하여 서로에게 알려주어야 한다. 이때 사설 IP를 보유한 장비들의 공인 IP정보를 알려주는 서버가 STUN이다.

자신의 공인 IP와 포트를 파악하여 서로에게 알려준다.

 

 * Web Topologies

   - Peer-to-peer (Mesh)

Peer To Peer (Mesh)

 세션의 각 참가자는 서버를 사용하지 않고 다른 모든 참가자와 직접 연결한다. 이런 종류의 연결은 비용이 가장 적고 설치하기 쉽기 때문에 작은 화상 회의에서 적절하다. 그러나 컨퍼런스가 커질 경우 CPU 사용량이 많아질 수 있기 때문에 모든 참가자들 간의 직접 연결 유지에 어려움을 겪게 된다. 모든 피어 사이간 개별 직접 연결 이기 때문에 메시 토폴로지는 녹화가 어렵다.

 낮은 대기 시간이 중요하고 녹화가 필요하지 않은 2~3명의 참가자를 연결하는 단순한 어플리케이션에 적절함다.

 

   - Selective Forwarding (SFU)

Selective Forwarding (SFU)

 세션의 각 참가자는 선택적 전달 장치(SFU) 역할을 하는 서버에 연결된다. 각 참가자는 암호화된 비디오 스트림을 서버에 한번 업로드한다. 서버는 그 스트림을 다른 참가자들에게 전달한다. 이것은 대기 시간을 줄이고 또한 피어 투 피어 연결에서 훨씬 더 어려운 SIP와 같은 다른 서버 측 통합과 같은 것들을 가능하게 한다.

 클라이언트 측에선 하나의 업스트림 연결만이 존재하므로 메시 토폴로지보다 업로딩 효율을 높이지만, 다운스트림은 참가자 수 만큼 존재한다. 업스트림에서의 여유로 참가자 수가 늘지만 클라이언트 자원 고갈에 의한 위상의 한계는 여전히 존재한다.

 여전히 낮은 대기 시간을 보증하며 기록이 필요하고 무결성이 중요한 4~10명의 참가자를 연결하는 어플리케이션에 적합하다. 균형잡힌 토폴로지로 간주된다.

 

   - Multipoint Control (Mixing)

Multipoint Control (Mixing)

 세션의 각 참가자는 다중 연결 제어장치(MCU) 역할을 하는 서버에 연결한다. 각 참가자로 부터 받은 미디어를 단일 스트림으로 합친 다음 각 클라이언트에게 제공한다. 서버 측면에서 대역폭 사용량과 다운스트림 연결에서 CPU 점유율 여유를 가져오지만 대신 오디오/비디오 미디어를 단일 스트림으로 합치기 위한 CPU 할당이 필요로 하다.

 가장 낮은 대역폭이기 때문에 네트워크 조건이 좋지 않을때 이점을 가지며, 위상의 제한이 없어 다수의 참가자 연결에 적절하다. 미디어를 서버에서 다루는 과정에서 낮은 레이턴시 보상을 받지 못한다.

 

 * WebRTC 보안

   - 브라우저 보호 : 기본적으로 브라우저 벤더에서 잠재적인 보안 위협이나 취약성을 보완해주는 부분이 있다.

   - 미디어 장치 접근 : 동의 없이 미디어 장치 자원 접근이 불가능하다.

   - 암호화 : 암호화는 WebRTC의 필수 사항이며 연결 설정 및 유지의 모든 부분에 적용된다. 이를 위해 선호하는 방법은 DTLS(Datagram Transport Layer Security) 핸드셰이크에 PFS(Perfect Forward Secrety)암호를 사용하여 키 데이터를 안전하게 교환하는 것이다. 오디오와 비디오의 경우, 키 데이터를 사용하여 AES(Advanced Encryption Standard) 키를 생성할 수 있으며, 이 키는 다시 SRTP(Secure Real-time Tranport Protocol)에서 미디어를 암호화 및 해독하는데 사용된다. WebRTC와 ORTC 모두 VoIP 시스템과 역 호환되고 상호운용 가능한 이 특정 스택을 의무화한다.

 

 


Reference

en.wikipedia.org/wiki/WebRTC

www.frozenmountain.com/ultimate-guide-to-webrtc

github.com/satanas/simple-signaling-server

 

+ Recent posts